Merge pull request #4063 from rust-lang/rustup-2024-11-28
Automatic Rustup
This commit is contained in:
commit
4624dadc20
1582 changed files with 11807 additions and 8468 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -65,7 +65,7 @@ jobs:
|
|||
defaults:
|
||||
run:
|
||||
shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
|
||||
timeout-minutes: 240
|
||||
timeout-minutes: 360
|
||||
env:
|
||||
CI_JOB_NAME: ${{ matrix.image }}
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||
|
|
|
|||
73
COPYRIGHT
73
COPYRIGHT
|
|
@ -343,49 +343,42 @@ their own copyright notices and license terms:
|
|||
* Portions of internationalization code use code or data from Unicode, which
|
||||
carry the following license:
|
||||
|
||||
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
|
||||
|
||||
See Terms of Use <https://www.unicode.org/copyright.html>
|
||||
for definitions of Unicode Inc.’s Data Files and Software.
|
||||
|
||||
NOTICE TO USER: Carefully read the following legal agreement.
|
||||
BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
|
||||
DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
|
||||
YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||
TERMS AND CONDITIONS OF THIS AGREEMENT.
|
||||
IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
|
||||
THE DATA FILES OR SOFTWARE.
|
||||
UNICODE LICENSE V3
|
||||
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright © 1991-2022 Unicode, Inc. All rights reserved.
|
||||
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
|
||||
Copyright © 1991-2024 Unicode, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Unicode data files and any associated documentation
|
||||
(the "Data Files") or Unicode software and any associated documentation
|
||||
(the "Software") to deal in the Data Files or Software
|
||||
without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
the Data Files or Software, and to permit persons to whom the Data Files
|
||||
or Software are furnished to do so, provided that either
|
||||
(a) this copyright and permission notice appear with all copies
|
||||
of the Data Files or Software, or
|
||||
(b) this copyright and permission notice appear in associated
|
||||
Documentation.
|
||||
NOTICE TO USER: Carefully read the following legal agreement. BY
|
||||
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
||||
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
|
||||
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of data files and any associated documentation (the "Data Files") or
|
||||
software and any associated documentation (the "Software") to deal in the
|
||||
Data Files or Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
copies of the Data Files or Software, and to permit persons to whom the
|
||||
Data Files or Software are furnished to do so, provided that either (a)
|
||||
this copyright and permission notice appear with all copies of the Data
|
||||
Files or Software, or (b) this copyright and permission notice appear in
|
||||
associated Documentation.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in these Data Files or Software without prior
|
||||
written authorization of the copyright holder.
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
THIRD PARTY RIGHTS.
|
||||
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
|
||||
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
|
||||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
|
||||
FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall
|
||||
not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in these Data Files or Software without prior written
|
||||
authorization of the copyright holder.
|
||||
|
|
|
|||
|
|
@ -411,9 +411,9 @@ version = "0.1.0"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.34"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9"
|
||||
checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
|
|
|||
39
LICENSES/Unicode-3.0.txt
Normal file
39
LICENSES/Unicode-3.0.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
UNICODE LICENSE V3
|
||||
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright © 1991-2024 Unicode, Inc.
|
||||
|
||||
NOTICE TO USER: Carefully read the following legal agreement. BY
|
||||
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
||||
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
|
||||
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of data files and any associated documentation (the "Data Files") or
|
||||
software and any associated documentation (the "Software") to deal in the
|
||||
Data Files or Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
copies of the Data Files or Software, and to permit persons to whom the
|
||||
Data Files or Software are furnished to do so, provided that either (a)
|
||||
this copyright and permission notice appear with all copies of the Data
|
||||
Files or Software, or (b) this copyright and permission notice appear in
|
||||
associated Documentation.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
THIRD PARTY RIGHTS.
|
||||
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
|
||||
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
|
||||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
|
||||
FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall
|
||||
not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in these Data Files or Software without prior written
|
||||
authorization of the copyright holder.
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
|
||||
|
||||
Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
|
||||
|
||||
Unicode Data Files do not include PDF online code charts under the directory http://www.unicode.org/Public/.
|
||||
|
||||
Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
|
||||
|
||||
NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
||||
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either
|
||||
|
||||
(a) this copyright and permission notice appear with all copies of the Data Files or Software, or
|
||||
(b) this copyright and permission notice appear in associated Documentation.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder.
|
||||
|
|
@ -28,6 +28,7 @@ path = [
|
|||
"COPYRIGHT",
|
||||
"INSTALL.md",
|
||||
"LICENSE-APACHE",
|
||||
"license-metadata.json",
|
||||
"LICENSE-MIT",
|
||||
"README.md",
|
||||
"RELEASES.md",
|
||||
|
|
@ -63,8 +64,8 @@ SPDX-License-Identifier = "Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT
|
|||
[[annotations]]
|
||||
path = "library/core/src/unicode/unicode_data.rs"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "1991-2022 Unicode, Inc. All rights reserved."
|
||||
SPDX-License-Identifier = "Unicode-DFS-2016"
|
||||
SPDX-FileCopyrightText = "1991-2024 Unicode, Inc."
|
||||
SPDX-License-Identifier = "Unicode-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "library/std/src/sync/mpmc/**"
|
||||
|
|
|
|||
|
|
@ -638,7 +638,7 @@ impl AddAssign for Size {
|
|||
#[cfg(feature = "nightly")]
|
||||
impl Step for Size {
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
|
||||
u64::steps_between(&start.bytes(), &end.bytes())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ pub use crate::format::*;
|
|||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
pub use crate::util::parser::ExprPrecedence;
|
||||
use crate::util::parser::{
|
||||
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
|
||||
};
|
||||
|
||||
/// A "Label" is an identifier of some point in sources,
|
||||
/// e.g. in the following code:
|
||||
|
|
@ -428,7 +430,15 @@ impl Default for WhereClause {
|
|||
|
||||
/// A single predicate in a where-clause.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum WherePredicate {
|
||||
pub struct WherePredicate {
|
||||
pub kind: WherePredicateKind,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Predicate kind in where-clause.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum WherePredicateKind {
|
||||
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
BoundPredicate(WhereBoundPredicate),
|
||||
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
|
||||
|
|
@ -437,22 +447,11 @@ pub enum WherePredicate {
|
|||
EqPredicate(WhereEqPredicate),
|
||||
}
|
||||
|
||||
impl WherePredicate {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
WherePredicate::BoundPredicate(p) => p.span,
|
||||
WherePredicate::RegionPredicate(p) => p.span,
|
||||
WherePredicate::EqPredicate(p) => p.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type bound.
|
||||
///
|
||||
/// E.g., `for<'c> Foo: Send + Clone + 'c`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct WhereBoundPredicate {
|
||||
pub span: Span,
|
||||
/// Any generics from a `for` binding.
|
||||
pub bound_generic_params: ThinVec<GenericParam>,
|
||||
/// The type being bounded.
|
||||
|
|
@ -466,7 +465,6 @@ pub struct WhereBoundPredicate {
|
|||
/// E.g., `'a: 'b + 'c`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct WhereRegionPredicate {
|
||||
pub span: Span,
|
||||
pub lifetime: Lifetime,
|
||||
pub bounds: GenericBounds,
|
||||
}
|
||||
|
|
@ -476,7 +474,6 @@ pub struct WhereRegionPredicate {
|
|||
/// E.g., `T = int`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct WhereEqPredicate {
|
||||
pub span: Span,
|
||||
pub lhs_ty: P<Ty>,
|
||||
pub rhs_ty: P<Ty>,
|
||||
}
|
||||
|
|
@ -1319,53 +1316,71 @@ impl Expr {
|
|||
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
|
||||
}
|
||||
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
pub fn precedence(&self) -> i8 {
|
||||
match self.kind {
|
||||
ExprKind::Array(_) => ExprPrecedence::Array,
|
||||
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
|
||||
ExprKind::Call(..) => ExprPrecedence::Call,
|
||||
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
|
||||
ExprKind::Tup(_) => ExprPrecedence::Tup,
|
||||
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
|
||||
ExprKind::Unary(..) => ExprPrecedence::Unary,
|
||||
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::While(..) => ExprPrecedence::While,
|
||||
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
|
||||
ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
||||
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
|
||||
ExprKind::Gen(..) => ExprPrecedence::Gen,
|
||||
ExprKind::Await(..) => ExprPrecedence::Await,
|
||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||
ExprKind::Index(..) => ExprPrecedence::Index,
|
||||
ExprKind::Range(..) => ExprPrecedence::Range,
|
||||
ExprKind::Underscore => ExprPrecedence::Path,
|
||||
ExprKind::Path(..) => ExprPrecedence::Path,
|
||||
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||
ExprKind::Paren(..) => ExprPrecedence::Paren,
|
||||
ExprKind::Try(..) => ExprPrecedence::Try,
|
||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
|
||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
||||
ExprKind::InlineAsm(..)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::OffsetOf(..)
|
||||
ExprKind::Closure(..) => PREC_CLOSURE,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
// ensures that `pprust` will add parentheses in the right places to get the desired
|
||||
// parse.
|
||||
ExprKind::Range(..) => PREC_RANGE,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
|
||||
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::AddrOf(..)
|
||||
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
||||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => PREC_PREFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Await(..)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::FormatArgs(..)
|
||||
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
|
||||
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
|
||||
| ExprKind::Gen(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::Lit(_)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::MacCall(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::OffsetOf(..)
|
||||
| ExprKind::Paren(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Try(..)
|
||||
| ExprKind::TryBlock(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Underscore
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3063,6 +3078,7 @@ pub struct FieldDef {
|
|||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub vis: Visibility,
|
||||
pub safety: Safety,
|
||||
pub ident: Option<Ident>,
|
||||
|
||||
pub ty: P<Ty>,
|
||||
|
|
|
|||
|
|
@ -332,7 +332,11 @@ pub trait MutVisitor: Sized {
|
|||
}
|
||||
|
||||
fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) {
|
||||
walk_where_predicate(self, where_predicate);
|
||||
walk_where_predicate(self, where_predicate)
|
||||
}
|
||||
|
||||
fn visit_where_predicate_kind(&mut self, kind: &mut WherePredicateKind) {
|
||||
walk_where_predicate_kind(self, kind)
|
||||
}
|
||||
|
||||
fn visit_vis(&mut self, vis: &mut Visibility) {
|
||||
|
|
@ -1065,26 +1069,30 @@ fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) {
|
|||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_where_predicate<T: MutVisitor>(vis: &mut T, pred: &mut WherePredicate) {
|
||||
match pred {
|
||||
WherePredicate::BoundPredicate(bp) => {
|
||||
let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp;
|
||||
pub fn walk_where_predicate<T: MutVisitor>(vis: &mut T, pred: &mut WherePredicate) {
|
||||
let WherePredicate { kind, id, span } = pred;
|
||||
vis.visit_id(id);
|
||||
vis.visit_where_predicate_kind(kind);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) {
|
||||
match kind {
|
||||
WherePredicateKind::BoundPredicate(bp) => {
|
||||
let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp;
|
||||
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_ty(bounded_ty);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
WherePredicate::RegionPredicate(rp) => {
|
||||
let WhereRegionPredicate { span, lifetime, bounds } = rp;
|
||||
WherePredicateKind::RegionPredicate(rp) => {
|
||||
let WhereRegionPredicate { lifetime, bounds } = rp;
|
||||
vis.visit_lifetime(lifetime);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
WherePredicate::EqPredicate(ep) => {
|
||||
let WhereEqPredicate { span, lhs_ty, rhs_ty } = ep;
|
||||
WherePredicateKind::EqPredicate(ep) => {
|
||||
let WhereEqPredicate { lhs_ty, rhs_ty } = ep;
|
||||
vis.visit_ty(lhs_ty);
|
||||
vis.visit_ty(rhs_ty);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1115,10 +1123,11 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
|
|||
}
|
||||
|
||||
pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = fd;
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = fd;
|
||||
visitor.visit_id(id);
|
||||
visit_attrs(visitor, attrs);
|
||||
visitor.visit_vis(vis);
|
||||
visit_safety(visitor, safety);
|
||||
visit_opt(ident, |ident| visitor.visit_ident(ident));
|
||||
visitor.visit_ty(ty);
|
||||
visitor.visit_span(span);
|
||||
|
|
|
|||
|
|
@ -237,121 +237,6 @@ pub const PREC_PREFIX: i8 = 50;
|
|||
pub const PREC_UNAMBIGUOUS: i8 = 60;
|
||||
pub const PREC_FORCE_PAREN: i8 = 100;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ExprPrecedence {
|
||||
Closure,
|
||||
Break,
|
||||
Continue,
|
||||
Ret,
|
||||
Yield,
|
||||
Yeet,
|
||||
Become,
|
||||
|
||||
Range,
|
||||
|
||||
Binary(BinOpKind),
|
||||
|
||||
Cast,
|
||||
|
||||
Assign,
|
||||
AssignOp,
|
||||
|
||||
AddrOf,
|
||||
Let,
|
||||
Unary,
|
||||
|
||||
Call,
|
||||
MethodCall,
|
||||
Field,
|
||||
Index,
|
||||
Try,
|
||||
Mac,
|
||||
|
||||
Array,
|
||||
Repeat,
|
||||
Tup,
|
||||
Lit,
|
||||
Path,
|
||||
Paren,
|
||||
If,
|
||||
While,
|
||||
ForLoop,
|
||||
Loop,
|
||||
Match,
|
||||
PostfixMatch,
|
||||
ConstBlock,
|
||||
Block,
|
||||
TryBlock,
|
||||
Struct,
|
||||
Gen,
|
||||
Await,
|
||||
Err,
|
||||
}
|
||||
|
||||
impl ExprPrecedence {
|
||||
pub fn order(self) -> i8 {
|
||||
match self {
|
||||
ExprPrecedence::Closure => PREC_CLOSURE,
|
||||
|
||||
ExprPrecedence::Break
|
||||
| ExprPrecedence::Continue
|
||||
| ExprPrecedence::Ret
|
||||
| ExprPrecedence::Yield
|
||||
| ExprPrecedence::Yeet
|
||||
| ExprPrecedence::Become => PREC_JUMP,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
// ensures that `pprust` will add parentheses in the right places to get the desired
|
||||
// parse.
|
||||
ExprPrecedence::Range => PREC_RANGE,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
|
||||
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
|
||||
|
||||
ExprPrecedence::Assign |
|
||||
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprPrecedence::AddrOf
|
||||
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
||||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprPrecedence::Let
|
||||
| ExprPrecedence::Unary => PREC_PREFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprPrecedence::Array
|
||||
| ExprPrecedence::Await
|
||||
| ExprPrecedence::Block
|
||||
| ExprPrecedence::Call
|
||||
| ExprPrecedence::ConstBlock
|
||||
| ExprPrecedence::Field
|
||||
| ExprPrecedence::ForLoop
|
||||
| ExprPrecedence::Gen
|
||||
| ExprPrecedence::If
|
||||
| ExprPrecedence::Index
|
||||
| ExprPrecedence::Lit
|
||||
| ExprPrecedence::Loop
|
||||
| ExprPrecedence::Mac
|
||||
| ExprPrecedence::Match
|
||||
| ExprPrecedence::MethodCall
|
||||
| ExprPrecedence::Paren
|
||||
| ExprPrecedence::Path
|
||||
| ExprPrecedence::PostfixMatch
|
||||
| ExprPrecedence::Repeat
|
||||
| ExprPrecedence::Struct
|
||||
| ExprPrecedence::Try
|
||||
| ExprPrecedence::TryBlock
|
||||
| ExprPrecedence::Tup
|
||||
| ExprPrecedence::While
|
||||
| ExprPrecedence::Err => PREC_UNAMBIGUOUS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
||||
pub fn prec_let_scrutinee_needs_par() -> usize {
|
||||
AssocOp::LAnd.precedence()
|
||||
|
|
|
|||
|
|
@ -192,6 +192,9 @@ pub trait Visitor<'ast>: Sized {
|
|||
fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
|
||||
walk_where_predicate(self, p)
|
||||
}
|
||||
fn visit_where_predicate_kind(&mut self, k: &'ast WherePredicateKind) -> Self::Result {
|
||||
walk_where_predicate_kind(self, k)
|
||||
}
|
||||
fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result {
|
||||
walk_fn(self, fk)
|
||||
}
|
||||
|
|
@ -794,22 +797,29 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(
|
|||
visitor: &mut V,
|
||||
predicate: &'a WherePredicate,
|
||||
) -> V::Result {
|
||||
match predicate {
|
||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||
let WherePredicate { kind, id: _, span: _ } = predicate;
|
||||
visitor.visit_where_predicate_kind(kind)
|
||||
}
|
||||
|
||||
pub fn walk_where_predicate_kind<'a, V: Visitor<'a>>(
|
||||
visitor: &mut V,
|
||||
kind: &'a WherePredicateKind,
|
||||
) -> V::Result {
|
||||
match kind {
|
||||
WherePredicateKind::BoundPredicate(WhereBoundPredicate {
|
||||
bounded_ty,
|
||||
bounds,
|
||||
bound_generic_params,
|
||||
span: _,
|
||||
}) => {
|
||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||
try_visit!(visitor.visit_ty(bounded_ty));
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||
}
|
||||
WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span: _ }) => {
|
||||
WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
|
||||
try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound));
|
||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||
}
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span: _ }) => {
|
||||
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||
try_visit!(visitor.visit_ty(lhs_ty));
|
||||
try_visit!(visitor.visit_ty(rhs_ty));
|
||||
}
|
||||
|
|
@ -961,7 +971,7 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>(
|
|||
}
|
||||
|
||||
pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result {
|
||||
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _ } = field;
|
||||
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _ } = field;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
visit_opt!(visitor, visit_ident, ident);
|
||||
|
|
|
|||
|
|
@ -152,6 +152,8 @@ ast_lowering_register2 = register `{$reg2_name}`
|
|||
|
||||
ast_lowering_register_class_only_clobber =
|
||||
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
|
||||
ast_lowering_register_class_only_clobber_stable =
|
||||
register class `{$reg_class_name}` can only be used as a clobber in stable
|
||||
|
||||
ast_lowering_register_conflict =
|
||||
register `{$reg1_name}` conflicts with register `{$reg2_name}`
|
||||
|
|
@ -181,6 +183,8 @@ ast_lowering_underscore_expr_lhs_assign =
|
|||
.label = `_` not allowed here
|
||||
|
||||
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
|
||||
using both label and output operands for inline assembly is unstable
|
||||
ast_lowering_unstable_inline_assembly_label_operands =
|
||||
label operands for inline assembly are unstable
|
||||
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ use super::errors::{
|
|||
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
||||
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
|
||||
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
|
||||
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
|
||||
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable,
|
||||
RegisterConflict,
|
||||
};
|
||||
use crate::{
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
||||
|
|
@ -61,6 +62,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
.emit();
|
||||
}
|
||||
}
|
||||
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
|
||||
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
|
||||
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
|
||||
&& !self.tcx.sess.opts.actually_rustdoc
|
||||
|
|
@ -239,15 +241,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
InlineAsmOperand::Label { block } => {
|
||||
if !self.tcx.features().asm_goto() {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::asm_goto,
|
||||
*op_sp,
|
||||
fluent::ast_lowering_unstable_inline_assembly_label_operands,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
|
||||
}
|
||||
};
|
||||
|
|
@ -333,11 +326,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// means that we disallow passing a value in/out of the asm and
|
||||
// require that the operand name an explicit register, not a
|
||||
// register class.
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
|
||||
self.dcx().emit_err(RegisterClassOnlyClobber {
|
||||
op_span: op_sp,
|
||||
reg_class_name: reg_class.name(),
|
||||
});
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap(), allow_experimental_reg)
|
||||
&& !op.is_clobber()
|
||||
{
|
||||
if allow_experimental_reg || reg_class.is_clobber_only(asm_arch.unwrap(), true)
|
||||
{
|
||||
// always clobber-only
|
||||
self.dcx().emit_err(RegisterClassOnlyClobber {
|
||||
op_span: op_sp,
|
||||
reg_class_name: reg_class.name(),
|
||||
});
|
||||
} else {
|
||||
// clobber-only in stable
|
||||
self.tcx
|
||||
.sess
|
||||
.create_feature_err(
|
||||
RegisterClassOnlyClobberStable {
|
||||
op_span: op_sp,
|
||||
reg_class_name: reg_class.name(),
|
||||
},
|
||||
sym::asm_experimental_reg,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -466,6 +477,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
// Feature gate checking for asm goto.
|
||||
if let Some((_, op_sp)) =
|
||||
operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. }))
|
||||
{
|
||||
if !self.tcx.features().asm_goto() {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::asm_goto,
|
||||
*op_sp,
|
||||
fluent::ast_lowering_unstable_inline_assembly_label_operands,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
// In addition, check if an output operand is used.
|
||||
// This is gated behind an additional feature.
|
||||
let output_operand_used = operands.iter().any(|(op, _)| {
|
||||
matches!(
|
||||
op,
|
||||
hir::InlineAsmOperand::Out { expr: Some(_), .. }
|
||||
| hir::InlineAsmOperand::InOut { .. }
|
||||
| hir::InlineAsmOperand::SplitInOut { out_expr: Some(_), .. }
|
||||
)
|
||||
});
|
||||
if output_operand_used && !self.tcx.features().asm_goto_with_outputs() {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::asm_goto_with_outputs,
|
||||
*op_sp,
|
||||
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
let operands = self.arena.alloc_from_iter(operands);
|
||||
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
||||
let template_strs = self.arena.alloc_from_iter(
|
||||
|
|
|
|||
|
|
@ -279,6 +279,14 @@ pub(crate) struct RegisterClassOnlyClobber {
|
|||
pub reg_class_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_class_only_clobber_stable)]
|
||||
pub(crate) struct RegisterClassOnlyClobberStable {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
pub reg_class_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_conflict)]
|
||||
pub(crate) struct RegisterConflict<'a> {
|
||||
|
|
|
|||
|
|
@ -381,15 +381,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn visit_where_predicate(&mut self, predicate: &'hir WherePredicate<'hir>) {
|
||||
match predicate {
|
||||
WherePredicate::BoundPredicate(pred) => {
|
||||
self.insert(pred.span, pred.hir_id, Node::WhereBoundPredicate(pred));
|
||||
self.with_parent(pred.hir_id, |this| {
|
||||
intravisit::walk_where_predicate(this, predicate)
|
||||
})
|
||||
}
|
||||
_ => intravisit::walk_where_predicate(self, predicate),
|
||||
}
|
||||
self.insert(predicate.span, predicate.hir_id, Node::WherePredicate(predicate));
|
||||
self.with_parent(predicate.hir_id, |this| {
|
||||
intravisit::walk_where_predicate(this, predicate)
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_array_length(&mut self, len: &'hir ArrayLen<'hir>) {
|
||||
|
|
|
|||
|
|
@ -724,6 +724,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
},
|
||||
vis_span: self.lower_span(f.vis.span),
|
||||
ty,
|
||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1400,7 +1401,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound`
|
||||
// checks both param bounds and where clauses for `?Sized`.
|
||||
for pred in &generics.where_clause.predicates {
|
||||
let WherePredicate::BoundPredicate(bound_pred) = pred else {
|
||||
let WherePredicateKind::BoundPredicate(bound_pred) = &pred.kind else {
|
||||
continue;
|
||||
};
|
||||
let compute_is_param = || {
|
||||
|
|
@ -1537,9 +1538,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
});
|
||||
let span = self.lower_span(span);
|
||||
|
||||
match kind {
|
||||
GenericParamKind::Const { .. } => None,
|
||||
let hir_id = self.next_id();
|
||||
let kind = self.arena.alloc(match kind {
|
||||
GenericParamKind::Const { .. } => return None,
|
||||
GenericParamKind::Type { .. } => {
|
||||
let def_id = self.local_def_id(id).to_def_id();
|
||||
let hir_id = self.next_id();
|
||||
|
|
@ -1554,38 +1555,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let ty_id = self.next_id();
|
||||
let bounded_ty =
|
||||
self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
|
||||
Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
hir_id: self.next_id(),
|
||||
hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bounded_ty: self.arena.alloc(bounded_ty),
|
||||
bounds,
|
||||
span,
|
||||
bound_generic_params: &[],
|
||||
origin,
|
||||
}))
|
||||
})
|
||||
}
|
||||
GenericParamKind::Lifetime => {
|
||||
let ident = self.lower_ident(ident);
|
||||
let lt_id = self.next_node_id();
|
||||
let lifetime = self.new_named_lifetime(id, lt_id, ident);
|
||||
Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime,
|
||||
span,
|
||||
bounds,
|
||||
in_where_clause: false,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
Some(hir::WherePredicate { hir_id, span, kind })
|
||||
}
|
||||
|
||||
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
|
||||
match pred {
|
||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||
let hir_id = self.lower_node_id(pred.id);
|
||||
let span = self.lower_span(pred.span);
|
||||
let kind = self.arena.alloc(match &pred.kind {
|
||||
WherePredicateKind::BoundPredicate(WhereBoundPredicate {
|
||||
bound_generic_params,
|
||||
bounded_ty,
|
||||
bounds,
|
||||
span,
|
||||
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
hir_id: self.next_id(),
|
||||
}) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params: self
|
||||
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
|
||||
bounded_ty: self
|
||||
|
|
@ -1594,12 +1593,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
),
|
||||
span: self.lower_span(*span),
|
||||
origin: PredicateOrigin::WhereClause,
|
||||
}),
|
||||
WherePredicate::RegionPredicate(WhereRegionPredicate { lifetime, bounds, span }) => {
|
||||
hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
span: self.lower_span(*span),
|
||||
WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
|
||||
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime: self.lower_lifetime(lifetime),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
|
|
@ -1608,15 +1605,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
in_where_clause: true,
|
||||
})
|
||||
}
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => {
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
|
||||
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
span: self.lower_span(*span),
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
hir::WherePredicate { hir_id, span, kind }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2117,11 +2117,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::ConstArgKind::Anon(ct)
|
||||
};
|
||||
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: ct_kind,
|
||||
is_desugared_from_effects: false,
|
||||
})
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
|
|
@ -2163,19 +2159,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
None,
|
||||
);
|
||||
|
||||
return ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Path(qpath),
|
||||
is_desugared_from_effects: false,
|
||||
};
|
||||
return ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) };
|
||||
}
|
||||
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||
is_desugared_from_effects: false,
|
||||
}
|
||||
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
|
|
|
|||
|
|
@ -1200,14 +1200,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
validate_generic_param_order(self.dcx(), &generics.params, generics.span);
|
||||
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
if let WherePredicate::EqPredicate(predicate) = predicate {
|
||||
deny_equality_constraints(self, predicate, generics);
|
||||
let span = predicate.span;
|
||||
if let WherePredicateKind::EqPredicate(predicate) = &predicate.kind {
|
||||
deny_equality_constraints(self, predicate, span, generics);
|
||||
}
|
||||
}
|
||||
walk_list!(self, visit_generic_param, &generics.params);
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
match predicate {
|
||||
WherePredicate::BoundPredicate(bound_pred) => {
|
||||
match &predicate.kind {
|
||||
WherePredicateKind::BoundPredicate(bound_pred) => {
|
||||
// This is slightly complicated. Our representation for poly-trait-refs contains a single
|
||||
// binder and thus we only allow a single level of quantification. However,
|
||||
// the syntax of Rust permits quantification in two places in where clauses,
|
||||
|
|
@ -1504,9 +1505,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
fn deny_equality_constraints(
|
||||
this: &AstValidator<'_>,
|
||||
predicate: &WhereEqPredicate,
|
||||
predicate_span: Span,
|
||||
generics: &Generics,
|
||||
) {
|
||||
let mut err = errors::EqualityInWhere { span: predicate.span, assoc: None, assoc2: None };
|
||||
let mut err = errors::EqualityInWhere { span: predicate_span, assoc: None, assoc2: None };
|
||||
|
||||
// Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind
|
||||
|
|
@ -1550,7 +1552,7 @@ fn deny_equality_constraints(
|
|||
}
|
||||
}
|
||||
err.assoc = Some(errors::AssociatedSuggestion {
|
||||
span: predicate.span,
|
||||
span: predicate_span,
|
||||
ident: *ident,
|
||||
param: param.ident,
|
||||
path: pprust::path_to_string(&assoc_path),
|
||||
|
|
@ -1580,23 +1582,23 @@ fn deny_equality_constraints(
|
|||
// We're removing th eonly where bound left, remove the whole thing.
|
||||
generics.where_clause.span
|
||||
} else {
|
||||
let mut span = predicate.span;
|
||||
let mut span = predicate_span;
|
||||
let mut prev: Option<Span> = None;
|
||||
let mut preds = generics.where_clause.predicates.iter().peekable();
|
||||
// Find the predicate that shouldn't have been in the where bound list.
|
||||
while let Some(pred) = preds.next() {
|
||||
if let WherePredicate::EqPredicate(pred) = pred
|
||||
&& pred.span == predicate.span
|
||||
if let WherePredicateKind::EqPredicate(_) = pred.kind
|
||||
&& pred.span == predicate_span
|
||||
{
|
||||
if let Some(next) = preds.peek() {
|
||||
// This is the first predicate, remove the trailing comma as well.
|
||||
span = span.with_hi(next.span().lo());
|
||||
span = span.with_hi(next.span.lo());
|
||||
} else if let Some(prev) = prev {
|
||||
// Remove the previous comma as well.
|
||||
span = span.with_lo(prev.hi());
|
||||
}
|
||||
}
|
||||
prev = Some(pred.span());
|
||||
prev = Some(pred.span);
|
||||
}
|
||||
span
|
||||
};
|
||||
|
|
@ -1613,8 +1615,8 @@ fn deny_equality_constraints(
|
|||
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
|
||||
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
|
||||
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
|
||||
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
|
||||
generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
|
||||
WherePredicateKind::BoundPredicate(p) => Some(&p.bounds),
|
||||
_ => None,
|
||||
}),
|
||||
) {
|
||||
|
|
@ -1637,8 +1639,8 @@ fn deny_equality_constraints(
|
|||
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
||||
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
|
||||
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
|
||||
WherePredicate::BoundPredicate(p)
|
||||
generics.where_clause.predicates.iter().filter_map(|pred| match &pred.kind {
|
||||
WherePredicateKind::BoundPredicate(p)
|
||||
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
|
||||
&& let [segment] = &path.segments[..] =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -345,8 +345,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
|
||||
fn visit_generics(&mut self, g: &'a ast::Generics) {
|
||||
for predicate in &g.where_clause.predicates {
|
||||
match predicate {
|
||||
ast::WherePredicate::BoundPredicate(bound_pred) => {
|
||||
match &predicate.kind {
|
||||
ast::WherePredicateKind::BoundPredicate(bound_pred) => {
|
||||
// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
|
||||
}
|
||||
|
|
@ -557,6 +557,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(global_registration, "global registration is experimental");
|
||||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < prec, fixup);
|
||||
}
|
||||
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
|
|
@ -615,7 +615,7 @@ impl<'a> State<'a> {
|
|||
expr,
|
||||
// Parenthesize if required by precedence, or in the
|
||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||
expr.precedence().order() < parser::PREC_JUMP
|
||||
expr.precedence() < parser::PREC_JUMP
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -191,6 +191,6 @@ impl FixupContext {
|
|||
/// "let chain".
|
||||
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
||||
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence().order())
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -726,11 +726,12 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
|
||||
match predicate {
|
||||
ast::WherePredicate::BoundPredicate(where_bound_predicate) => {
|
||||
let ast::WherePredicate { kind, id: _, span: _ } = predicate;
|
||||
match kind {
|
||||
ast::WherePredicateKind::BoundPredicate(where_bound_predicate) => {
|
||||
self.print_where_bound_predicate(where_bound_predicate);
|
||||
}
|
||||
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
||||
ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
|
||||
lifetime,
|
||||
bounds,
|
||||
..
|
||||
|
|
@ -742,7 +743,9 @@ impl<'a> State<'a> {
|
|||
self.print_lifetime_bounds(bounds);
|
||||
}
|
||||
}
|
||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
|
||||
ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate {
|
||||
lhs_ty, rhs_ty, ..
|
||||
}) => {
|
||||
self.print_type(lhs_ty);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
|
|
|
|||
|
|
@ -1062,8 +1062,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
&& let spans = hir_generics
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|pred| match pred {
|
||||
hir::WherePredicate::BoundPredicate(pred) => Some(pred),
|
||||
.filter_map(|pred| match pred.kind {
|
||||
hir::WherePredicateKind::BoundPredicate(pred) => Some(pred),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|pred| {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::GenericBound::Trait;
|
||||
use rustc_hir::QPath::Resolved;
|
||||
use rustc_hir::WherePredicate::BoundPredicate;
|
||||
use rustc_hir::WherePredicateKind::BoundPredicate;
|
||||
use rustc_hir::def::Res::Def;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -236,7 +236,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let mut hrtb_bounds = vec![];
|
||||
gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
|
||||
for pred in generics.predicates {
|
||||
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) = pred
|
||||
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
|
||||
pred.kind
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -267,12 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
};
|
||||
debug!(?generics_fn);
|
||||
generics_fn.predicates.iter().for_each(|predicate| {
|
||||
let BoundPredicate(WhereBoundPredicate {
|
||||
span: bounded_span,
|
||||
bounded_ty,
|
||||
bounds,
|
||||
..
|
||||
}) = predicate
|
||||
let BoundPredicate(WhereBoundPredicate { bounded_ty, bounds, .. }) = predicate.kind
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -287,7 +283,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
.rfind(|param| param.def_id.to_def_id() == defid)
|
||||
.is_some()
|
||||
{
|
||||
suggestions.push((bounded_span.shrink_to_hi(), " + 'static".to_string()));
|
||||
suggestions.push((predicate.span.shrink_to_hi(), " + 'static".to_string()));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -300,7 +300,10 @@ pub fn parse_asm_args<'a>(
|
|||
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
|
||||
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
|
||||
}
|
||||
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
|
||||
if args.options.contains(ast::InlineAsmOptions::NORETURN)
|
||||
&& !outputs_sp.is_empty()
|
||||
&& labels_sp.is_empty()
|
||||
{
|
||||
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
|
||||
// Bail out now since this is likely to confuse MIR
|
||||
return Err(err);
|
||||
|
|
|
|||
|
|
@ -288,19 +288,18 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
//
|
||||
// We should also write a few new `where` bounds from `#[pointee] T` to `__S`
|
||||
// as well as any bound that indirectly involves the `#[pointee] T` type.
|
||||
for bound in &generics.where_clause.predicates {
|
||||
if let ast::WherePredicate::BoundPredicate(bound) = bound {
|
||||
for predicate in &generics.where_clause.predicates {
|
||||
if let ast::WherePredicateKind::BoundPredicate(bound) = &predicate.kind {
|
||||
let mut substitution = TypeSubstitution {
|
||||
from_name: pointee_ty_ident.name,
|
||||
to_ty: &s_ty,
|
||||
rewritten: false,
|
||||
};
|
||||
let mut predicate = ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||
span: bound.span,
|
||||
bound_generic_params: bound.bound_generic_params.clone(),
|
||||
bounded_ty: bound.bounded_ty.clone(),
|
||||
bounds: bound.bounds.clone(),
|
||||
});
|
||||
let mut predicate = ast::WherePredicate {
|
||||
kind: ast::WherePredicateKind::BoundPredicate(bound.clone()),
|
||||
span: predicate.span,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
};
|
||||
substitution.visit_where_predicate(&mut predicate);
|
||||
if substitution.rewritten {
|
||||
impl_generics.where_clause.predicates.push(predicate);
|
||||
|
|
@ -319,7 +318,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
|
||||
fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
|
||||
for bound in predicates {
|
||||
if let ast::WherePredicate::BoundPredicate(bound) = bound
|
||||
if let ast::WherePredicateKind::BoundPredicate(bound) = &bound.kind
|
||||
&& bound.bounded_ty.kind.is_simple_path().is_some_and(|name| name == pointee)
|
||||
{
|
||||
for bound in &bound.bounds {
|
||||
|
|
@ -385,8 +384,8 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
|||
}
|
||||
|
||||
fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) {
|
||||
match where_predicate {
|
||||
rustc_ast::WherePredicate::BoundPredicate(bound) => {
|
||||
match &mut where_predicate.kind {
|
||||
rustc_ast::WherePredicateKind::BoundPredicate(bound) => {
|
||||
bound
|
||||
.bound_generic_params
|
||||
.flat_map_in_place(|param| self.flat_map_generic_param(param));
|
||||
|
|
@ -395,8 +394,8 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
|||
self.visit_param_bound(bound, BoundKind::Bound)
|
||||
}
|
||||
}
|
||||
rustc_ast::WherePredicate::RegionPredicate(_)
|
||||
| rustc_ast::WherePredicate::EqPredicate(_) => {}
|
||||
rustc_ast::WherePredicateKind::RegionPredicate(_)
|
||||
| rustc_ast::WherePredicateKind::EqPredicate(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -690,25 +690,10 @@ impl<'a> TraitDef<'a> {
|
|||
|
||||
// and similarly for where clauses
|
||||
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
|
||||
match clause {
|
||||
ast::WherePredicate::BoundPredicate(wb) => {
|
||||
let span = wb.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||
span,
|
||||
..wb.clone()
|
||||
})
|
||||
}
|
||||
ast::WherePredicate::RegionPredicate(wr) => {
|
||||
let span = wr.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
||||
span,
|
||||
..wr.clone()
|
||||
})
|
||||
}
|
||||
ast::WherePredicate::EqPredicate(we) => {
|
||||
let span = we.span.with_ctxt(ctxt);
|
||||
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() })
|
||||
}
|
||||
ast::WherePredicate {
|
||||
kind: clause.kind.clone(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: clause.span.with_ctxt(ctxt),
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -757,13 +742,14 @@ impl<'a> TraitDef<'a> {
|
|||
|
||||
if !bounds.is_empty() {
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
bounded_ty: field_ty_param.ty,
|
||||
bounds,
|
||||
};
|
||||
|
||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||
let kind = ast::WherePredicateKind::BoundPredicate(predicate);
|
||||
let predicate =
|
||||
ast::WherePredicate { kind, id: ast::DUMMY_NODE_ID, span: self.span };
|
||||
where_clause.predicates.push(predicate);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ pub(crate) fn get_function_sig<'tcx>(
|
|||
clif_sig_from_fn_abi(
|
||||
tcx,
|
||||
default_call_conv,
|
||||
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
|
||||
&FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -438,9 +438,9 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.node.ty(fx.mir, fx.tcx))),
|
||||
);
|
||||
let fn_abi = if let Some(instance) = instance {
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
|
||||
FullyMonomorphizedLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
|
||||
} else {
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
||||
FullyMonomorphizedLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
|
||||
};
|
||||
|
||||
let is_cold = if fn_sig.abi() == ExternAbi::RustCold {
|
||||
|
|
@ -721,8 +721,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
||||
args: drop_instance.args,
|
||||
};
|
||||
let fn_abi =
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx)
|
||||
.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
|
||||
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
||||
let sig = fx.bcx.import_signature(sig);
|
||||
|
|
@ -764,8 +764,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0),
|
||||
args: drop_instance.args,
|
||||
};
|
||||
let fn_abi =
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx)
|
||||
.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||
|
||||
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
|
||||
let sig = fx.bcx.import_signature(sig);
|
||||
|
|
@ -774,8 +774,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
_ => {
|
||||
assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _)));
|
||||
|
||||
let fn_abi =
|
||||
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
|
||||
let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx)
|
||||
.fn_abi_of_instance(drop_instance, ty::List::empty());
|
||||
|
||||
let arg_value = drop_place.place_ref(
|
||||
fx,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
let block_map: IndexVec<BasicBlock, Block> =
|
||||
(0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect();
|
||||
|
||||
let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty());
|
||||
let fn_abi = FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty());
|
||||
|
||||
// Make FunctionCx
|
||||
let target_config = module.target_config();
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
|
|||
impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty)
|
||||
FullyMonomorphizedLayoutCx(self.tcx).handle_layout_err(err, span, ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
|
|||
span: Span,
|
||||
fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> ! {
|
||||
RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
|
||||
FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -443,9 +443,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
|
||||
pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
|
||||
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||
|
|
@ -459,7 +459,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
||||
impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
#[inline]
|
||||
fn handle_fn_abi_err(
|
||||
&self,
|
||||
|
|
@ -485,25 +485,25 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
|
||||
impl<'tcx> layout::HasTyCtxt<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
|
||||
impl<'tcx> rustc_abi::HasDataLayout for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||
&self.0.data_layout
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> layout::HasTypingEnv<'tcx> for RevealAllLayoutCx<'tcx> {
|
||||
impl<'tcx> layout::HasTypingEnv<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
||||
ty::TypingEnv::fully_monomorphized()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> {
|
||||
impl<'tcx> HasTargetSpec for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
fn target_spec(&self) -> &Target {
|
||||
&self.0.sess.target
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
use crate::{DebugContext, RevealAllLayoutCx, has_ptr_meta};
|
||||
use crate::{DebugContext, FullyMonomorphizedLayoutCx, has_ptr_meta};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct TypeDebugContext<'tcx> {
|
||||
|
|
@ -85,7 +85,7 @@ impl DebugContext {
|
|||
type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(encoding));
|
||||
type_entry.set(
|
||||
gimli::DW_AT_byte_size,
|
||||
AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()),
|
||||
AttributeValue::Udata(FullyMonomorphizedLayoutCx(tcx).layout_of(ty).size.bytes()),
|
||||
);
|
||||
|
||||
type_id
|
||||
|
|
@ -159,7 +159,7 @@ impl DebugContext {
|
|||
return_if_type_created_in_meantime!(type_dbg, tuple_type);
|
||||
|
||||
let name = type_names::compute_debuginfo_type_name(tcx, tuple_type, false);
|
||||
let layout = RevealAllLayoutCx(tcx).layout_of(tuple_type);
|
||||
let layout = FullyMonomorphizedLayoutCx(tcx).layout_of(tuple_type);
|
||||
|
||||
let tuple_type_id =
|
||||
self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_structure_type);
|
||||
|
|
@ -178,7 +178,9 @@ impl DebugContext {
|
|||
member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty));
|
||||
member_entry.set(
|
||||
gimli::DW_AT_alignment,
|
||||
AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).align.pref.bytes()),
|
||||
AttributeValue::Udata(
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.pref.bytes(),
|
||||
),
|
||||
);
|
||||
member_entry.set(
|
||||
gimli::DW_AT_data_member_location,
|
||||
|
|
@ -198,7 +200,11 @@ impl DebugContext {
|
|||
self.debug_type(
|
||||
tcx,
|
||||
type_dbg,
|
||||
Ty::new_array(tcx, tcx.types.u8, RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()),
|
||||
Ty::new_array(
|
||||
tcx,
|
||||
tcx.types.u8,
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty).size.bytes(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
|
|||
tcx,
|
||||
op_sp,
|
||||
const_value,
|
||||
RevealAllLayoutCx(tcx).layout_of(ty),
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty),
|
||||
);
|
||||
global_asm.push_str(&string);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ pub(crate) fn codegen_naked_asm<'tcx>(
|
|||
tcx,
|
||||
span,
|
||||
const_value,
|
||||
RevealAllLayoutCx(tcx).layout_of(cv.ty()),
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(cv.ty()),
|
||||
);
|
||||
CInlineAsmOperand::Const { value }
|
||||
}
|
||||
|
|
@ -462,8 +462,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||
let mut slots_output = vec![None; self.operands.len()];
|
||||
|
||||
let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| {
|
||||
let reg_size =
|
||||
reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap();
|
||||
let reg_size = reg_class
|
||||
.supported_types(self.arch, true)
|
||||
.iter()
|
||||
.map(|(ty, _)| ty.size())
|
||||
.max()
|
||||
.unwrap();
|
||||
let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap();
|
||||
let offset = slot_size.align_to(align);
|
||||
*slot_size = offset + reg_size;
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
// `clobber_abi` can add lots of clobbers that are not supported by the target,
|
||||
// such as AVX-512 registers, so we just ignore unsupported registers
|
||||
let is_target_supported =
|
||||
reg.reg_class().supported_types(asm_arch).iter().any(
|
||||
reg.reg_class().supported_types(asm_arch, true).iter().any(
|
||||
|&(_, feature)| {
|
||||
if let Some(feature) = feature {
|
||||
self.tcx
|
||||
|
|
@ -683,9 +683,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
|||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::S390x(
|
||||
S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg,
|
||||
) => {
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
|
||||
|
|
@ -766,7 +765,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr,
|
||||
) => cx.type_i32(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
match *op {
|
||||
InlineAsmOperandRef::Out { reg, late, place } => {
|
||||
let is_target_supported = |reg_class: InlineAsmRegClass| {
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch) {
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch, true) {
|
||||
if let Some(feature) = feature {
|
||||
if self
|
||||
.tcx
|
||||
|
|
@ -85,7 +85,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
continue;
|
||||
} else if !is_target_supported(reg.reg_class())
|
||||
|| reg.reg_class().is_clobber_only(asm_arch)
|
||||
|| reg.reg_class().is_clobber_only(asm_arch, true)
|
||||
{
|
||||
// We turn discarded outputs into clobber constraints
|
||||
// if the target feature needed by the register class is
|
||||
|
|
@ -342,24 +342,32 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
|
||||
|
||||
// Switch to the 'normal' basic block if we did an `invoke` instead of a `call`
|
||||
if let Some(dest) = dest {
|
||||
self.switch_to_block(dest);
|
||||
}
|
||||
// Write results to outputs. We need to do this for all possible control flow.
|
||||
//
|
||||
// Note that `dest` maybe populated with unreachable_block when asm goto with outputs
|
||||
// is used (because we need to codegen callbr which always needs a destination), so
|
||||
// here we use the NORETURN option to determine if `dest` should be used.
|
||||
for block in (if options.contains(InlineAsmOptions::NORETURN) { None } else { Some(dest) })
|
||||
.into_iter()
|
||||
.chain(labels.iter().copied().map(Some))
|
||||
{
|
||||
if let Some(block) = block {
|
||||
self.switch_to_block(block);
|
||||
}
|
||||
|
||||
// Write results to outputs
|
||||
for (idx, op) in operands.iter().enumerate() {
|
||||
if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
|
||||
| InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
|
||||
{
|
||||
let value = if output_types.len() == 1 {
|
||||
result
|
||||
} else {
|
||||
self.extract_value(result, op_idx[&idx] as u64)
|
||||
};
|
||||
let value =
|
||||
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
|
||||
OperandValue::Immediate(value).store(self, place);
|
||||
for (idx, op) in operands.iter().enumerate() {
|
||||
if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
|
||||
| InlineAsmOperandRef::InOut { reg, out_place: Some(place), .. } = *op
|
||||
{
|
||||
let value = if output_types.len() == 1 {
|
||||
result
|
||||
} else {
|
||||
self.extract_value(result, op_idx[&idx] as u64)
|
||||
};
|
||||
let value =
|
||||
llvm_fixup_output(self, value, reg.reg_class(), &place.layout, instance);
|
||||
OperandValue::Immediate(value).store(self, place);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -678,7 +686,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
|
|||
S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
|
||||
S390x(S390xInlineAsmRegClass::vreg) => "v",
|
||||
S390x(S390xInlineAsmRegClass::areg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
Sparc(SparcInlineAsmRegClass::reg) => "r",
|
||||
|
|
@ -844,7 +853,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
|
|||
Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
|
||||
S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(),
|
||||
S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => {
|
||||
S390x(S390xInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i64(), 2),
|
||||
S390x(S390xInlineAsmRegClass::areg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
Sparc(SparcInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
|
|
|
|||
|
|
@ -955,24 +955,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) ->
|
|||
}
|
||||
}
|
||||
|
||||
/// Embed the bitcode of an LLVM module in the LLVM module itself.
|
||||
///
|
||||
/// This is done primarily for iOS where it appears to be standard to compile C
|
||||
/// code at least with `-fembed-bitcode` which creates two sections in the
|
||||
/// executable:
|
||||
///
|
||||
/// * __LLVM,__bitcode
|
||||
/// * __LLVM,__cmdline
|
||||
///
|
||||
/// It appears *both* of these sections are necessary to get the linker to
|
||||
/// recognize what's going on. A suitable cmdline value is taken from the
|
||||
/// target spec.
|
||||
///
|
||||
/// Furthermore debug/O1 builds don't actually embed bitcode but rather just
|
||||
/// embed an empty section.
|
||||
///
|
||||
/// Basically all of this is us attempting to follow in the footsteps of clang
|
||||
/// on iOS. See #35968 for lots more info.
|
||||
/// Embed the bitcode of an LLVM module for LTO in the LLVM module itself.
|
||||
unsafe fn embed_bitcode(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
llcx: &llvm::Context,
|
||||
|
|
|
|||
|
|
@ -172,3 +172,12 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
|
|||
Visibility::Protected => llvm::Visibility::Protected,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) {
|
||||
if attrs.no_sanitize.contains(SanitizerSet::ADDRESS) {
|
||||
unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) };
|
||||
}
|
||||
if attrs.no_sanitize.contains(SanitizerSet::HWADDRESS) {
|
||||
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,6 +470,8 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
base::set_link_section(g, attrs);
|
||||
}
|
||||
|
||||
base::set_variable_sanitizer_attrs(g, attrs);
|
||||
|
||||
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
|
||||
// `USED` and `USED_LINKER` can't be used together.
|
||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
|
||||
|
||||
use crate::coverageinfo::mapgen::LocalFileId;
|
||||
use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId};
|
||||
|
||||
/// Must match the layout of `LLVMRustCounterKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -126,37 +124,23 @@ pub(crate) struct CoverageSpan {
|
|||
/// Local index into the function's local-to-global file ID table.
|
||||
/// The value at that index is itself an index into the coverage filename
|
||||
/// table in the CGU's `__llvm_covmap` section.
|
||||
file_id: u32,
|
||||
pub(crate) file_id: u32,
|
||||
|
||||
/// 1-based starting line of the source code span.
|
||||
start_line: u32,
|
||||
pub(crate) start_line: u32,
|
||||
/// 1-based starting column of the source code span.
|
||||
start_col: u32,
|
||||
pub(crate) start_col: u32,
|
||||
/// 1-based ending line of the source code span.
|
||||
end_line: u32,
|
||||
pub(crate) end_line: u32,
|
||||
/// 1-based ending column of the source code span. High bit must be unset.
|
||||
end_col: u32,
|
||||
}
|
||||
|
||||
impl CoverageSpan {
|
||||
pub(crate) fn from_source_region(
|
||||
local_file_id: LocalFileId,
|
||||
code_region: &SourceRegion,
|
||||
) -> Self {
|
||||
let file_id = local_file_id.as_u32();
|
||||
let &SourceRegion { start_line, start_col, end_line, end_col } = code_region;
|
||||
// Internally, LLVM uses the high bit of `end_col` to distinguish between
|
||||
// code regions and gap regions, so it can't be used by the column number.
|
||||
assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
|
||||
Self { file_id, start_line, start_col, end_line, end_col }
|
||||
}
|
||||
pub(crate) end_col: u32,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageCodeRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct CodeRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) counter: Counter,
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +148,7 @@ pub(crate) struct CodeRegion {
|
|||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct BranchRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
}
|
||||
|
|
@ -173,7 +157,7 @@ pub(crate) struct BranchRegion {
|
|||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCBranchRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
pub(crate) mcdc_branch_params: mcdc::BranchParameters,
|
||||
|
|
@ -183,6 +167,6 @@ pub(crate) struct MCDCBranchRegion {
|
|||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCDecisionRegion {
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, MappingKind, Op,
|
||||
SourceRegion,
|
||||
};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
|
||||
|
|
@ -220,16 +220,16 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Converts this function's coverage mappings into an intermediate form
|
||||
/// that will be used by `mapgen` when preparing for FFI.
|
||||
pub(crate) fn counter_regions(
|
||||
/// Yields all this function's coverage mappings, after simplifying away
|
||||
/// unused counters and counter expressions.
|
||||
pub(crate) fn mapping_spans(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (MappingKind, &SourceRegion)> + ExactSizeIterator {
|
||||
) -> impl Iterator<Item = (MappingKind, Span)> + ExactSizeIterator + Captures<'_> {
|
||||
self.function_coverage_info.mappings.iter().map(move |mapping| {
|
||||
let Mapping { kind, source_region } = mapping;
|
||||
let &Mapping { ref kind, span } = mapping;
|
||||
let kind =
|
||||
kind.map_terms(|term| if self.is_zero_term(term) { CovTerm::Zero } else { term });
|
||||
(kind, source_region)
|
||||
(kind, span)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
mod spans;
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools as _;
|
||||
use rustc_abi::Align;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::MappingKind;
|
||||
|
|
@ -15,7 +17,7 @@ use rustc_middle::{bug, mir};
|
|||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::def_id::DefIdSet;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_span::{SourceFile, StableSourceFileId};
|
||||
use rustc_target::spec::HasTargetSpec;
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -72,11 +74,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
.map(|(instance, function_coverage)| (instance, function_coverage.into_finished()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let all_file_names = function_coverage_entries
|
||||
let all_files = function_coverage_entries
|
||||
.iter()
|
||||
.map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span)
|
||||
.map(|span| span_file_name(tcx, span));
|
||||
let global_file_table = GlobalFileTable::new(all_file_names);
|
||||
.map(|span| tcx.sess.source_map().lookup_source_file(span.lo()));
|
||||
let global_file_table = GlobalFileTable::new(all_files);
|
||||
|
||||
// Encode all filenames referenced by coverage mappings in this CGU.
|
||||
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
||||
|
|
@ -103,15 +105,8 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
encode_mappings_for_function(tcx, &global_file_table, &function_coverage);
|
||||
|
||||
if coverage_mapping_buffer.is_empty() {
|
||||
if function_coverage.is_used() {
|
||||
bug!(
|
||||
"A used function should have had coverage mapping data but did not: {}",
|
||||
mangled_function_name
|
||||
);
|
||||
} else {
|
||||
debug!("unused function had no coverage mapping data: {}", mangled_function_name);
|
||||
continue;
|
||||
}
|
||||
debug!("function has no mappings to embed; skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
if !is_used {
|
||||
|
|
@ -148,29 +143,34 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying source files.
|
||||
struct GlobalFileTable {
|
||||
/// This "raw" table doesn't include the working dir, so a filename's
|
||||
/// This "raw" table doesn't include the working dir, so a file's
|
||||
/// global ID is its index in this set **plus one**.
|
||||
raw_file_table: FxIndexSet<Symbol>,
|
||||
raw_file_table: FxIndexMap<StableSourceFileId, Arc<SourceFile>>,
|
||||
}
|
||||
|
||||
impl GlobalFileTable {
|
||||
fn new(all_file_names: impl IntoIterator<Item = Symbol>) -> Self {
|
||||
// Collect all of the filenames into a set. Filenames usually come in
|
||||
// contiguous runs, so we can dedup adjacent ones to save work.
|
||||
let mut raw_file_table = all_file_names.into_iter().dedup().collect::<FxIndexSet<Symbol>>();
|
||||
fn new(all_files: impl IntoIterator<Item = Arc<SourceFile>>) -> Self {
|
||||
// Collect all of the files into a set. Files usually come in contiguous
|
||||
// runs, so we can dedup adjacent ones to save work.
|
||||
let mut raw_file_table = all_files
|
||||
.into_iter()
|
||||
.dedup_by(|a, b| a.stable_id == b.stable_id)
|
||||
.map(|f| (f.stable_id, f))
|
||||
.collect::<FxIndexMap<StableSourceFileId, Arc<SourceFile>>>();
|
||||
|
||||
// Sort the file table by its actual string values, not the arbitrary
|
||||
// ordering of its symbols.
|
||||
raw_file_table.sort_unstable_by(|a, b| a.as_str().cmp(b.as_str()));
|
||||
// Sort the file table by its underlying filenames.
|
||||
raw_file_table.sort_unstable_by(|_, a, _, b| {
|
||||
Ord::cmp(&a.name, &b.name).then_with(|| Ord::cmp(&a.stable_id, &b.stable_id))
|
||||
});
|
||||
|
||||
Self { raw_file_table }
|
||||
}
|
||||
|
||||
fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId {
|
||||
let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| {
|
||||
bug!("file name not found in prepared global file table: {file_name}");
|
||||
fn global_file_id_for_file(&self, file: &SourceFile) -> GlobalFileId {
|
||||
let raw_id = self.raw_file_table.get_index_of(&file.stable_id).unwrap_or_else(|| {
|
||||
bug!("file not found in prepared global file table: {:?}", file.name);
|
||||
});
|
||||
// The raw file table doesn't include an entry for the working dir
|
||||
// (which has ID 0), so add 1 to get the correct ID.
|
||||
|
|
@ -178,24 +178,27 @@ impl GlobalFileTable {
|
|||
}
|
||||
|
||||
fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
|
||||
let mut table = Vec::with_capacity(self.raw_file_table.len() + 1);
|
||||
|
||||
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
|
||||
// requires setting the first filename to the compilation directory.
|
||||
// Since rustc generates coverage maps with relative paths, the
|
||||
// compilation directory can be combined with the relative paths
|
||||
// to get absolute paths, if needed.
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
let working_dir: &str = &tcx
|
||||
.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy();
|
||||
table.push(
|
||||
tcx.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy(),
|
||||
);
|
||||
|
||||
// Insert the working dir at index 0, before the other filenames.
|
||||
let filenames =
|
||||
iter::once(working_dir).chain(self.raw_file_table.iter().map(Symbol::as_str));
|
||||
llvm_cov::write_filenames_to_buffer(filenames)
|
||||
// Add the regular entries after the base directory.
|
||||
table.extend(self.raw_file_table.values().map(|file| {
|
||||
file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
|
||||
}));
|
||||
|
||||
llvm_cov::write_filenames_to_buffer(table.iter().map(|f| f.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +211,7 @@ rustc_index::newtype_index! {
|
|||
/// An index into a function's list of global file IDs. That underlying list
|
||||
/// of local-to-global mappings will be embedded in the function's record in
|
||||
/// the `__llvm_covfun` linker section.
|
||||
pub(crate) struct LocalFileId {}
|
||||
struct LocalFileId {}
|
||||
}
|
||||
|
||||
/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
|
||||
|
|
@ -234,13 +237,6 @@ impl VirtualFileMapping {
|
|||
}
|
||||
}
|
||||
|
||||
fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
|
||||
let source_file = tcx.sess.source_map().lookup_source_file(span.lo());
|
||||
let name =
|
||||
source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy();
|
||||
Symbol::intern(&name)
|
||||
}
|
||||
|
||||
/// Using the expressions and counter regions collected for a single function,
|
||||
/// generate the variable-sized payload of its corresponding `__llvm_covfun`
|
||||
/// entry. The payload is returned as a vector of bytes.
|
||||
|
|
@ -251,11 +247,13 @@ fn encode_mappings_for_function(
|
|||
global_file_table: &GlobalFileTable,
|
||||
function_coverage: &FunctionCoverage<'_>,
|
||||
) -> Vec<u8> {
|
||||
let counter_regions = function_coverage.counter_regions();
|
||||
if counter_regions.is_empty() {
|
||||
let mapping_spans = function_coverage.mapping_spans();
|
||||
if mapping_spans.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let fn_cov_info = function_coverage.function_coverage_info;
|
||||
|
||||
let expressions = function_coverage.counter_expressions().collect::<Vec<_>>();
|
||||
|
||||
let mut virtual_file_mapping = VirtualFileMapping::default();
|
||||
|
|
@ -265,34 +263,39 @@ fn encode_mappings_for_function(
|
|||
let mut mcdc_decision_regions = vec![];
|
||||
|
||||
// Currently a function's mappings must all be in the same file as its body span.
|
||||
let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
|
||||
let source_map = tcx.sess.source_map();
|
||||
let source_file = source_map.lookup_source_file(fn_cov_info.body_span.lo());
|
||||
|
||||
// Look up the global file ID for that filename.
|
||||
let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
|
||||
// Look up the global file ID for that file.
|
||||
let global_file_id = global_file_table.global_file_id_for_file(&source_file);
|
||||
|
||||
// Associate that global file ID with a local file ID for this function.
|
||||
let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
|
||||
debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
|
||||
|
||||
// For each counter/region pair in this function+file, convert it to a
|
||||
let make_cov_span = |span| {
|
||||
spans::make_coverage_span(local_file_id, source_map, fn_cov_info, &source_file, span)
|
||||
};
|
||||
|
||||
// For each coverage mapping span in this function+file, convert it to a
|
||||
// form suitable for FFI.
|
||||
for (mapping_kind, region) in counter_regions {
|
||||
debug!("Adding counter {mapping_kind:?} to map for {region:?}");
|
||||
let span = ffi::CoverageSpan::from_source_region(local_file_id, region);
|
||||
for (mapping_kind, span) in mapping_spans {
|
||||
debug!("Adding counter {mapping_kind:?} to map for {span:?}");
|
||||
let Some(cov_span) = make_cov_span(span) else { continue };
|
||||
match mapping_kind {
|
||||
MappingKind::Code(term) => {
|
||||
code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
|
||||
code_regions
|
||||
.push(ffi::CodeRegion { cov_span, counter: ffi::Counter::from_term(term) });
|
||||
}
|
||||
MappingKind::Branch { true_term, false_term } => {
|
||||
branch_regions.push(ffi::BranchRegion {
|
||||
span,
|
||||
cov_span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
|
||||
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
|
||||
span,
|
||||
cov_span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
|
||||
|
|
@ -300,7 +303,7 @@ fn encode_mappings_for_function(
|
|||
}
|
||||
MappingKind::MCDCDecision(mcdc_decision_params) => {
|
||||
mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
|
||||
span,
|
||||
cov_span,
|
||||
mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
124
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
Normal file
124
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
use rustc_middle::mir::coverage::FunctionCoverageInfo;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, Pos, SourceFile, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::coverageinfo::ffi;
|
||||
use crate::coverageinfo::mapgen::LocalFileId;
|
||||
|
||||
/// Converts the span into its start line and column, and end line and column.
|
||||
///
|
||||
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
|
||||
/// the compiler, these column numbers are denoted in **bytes**, because that's what
|
||||
/// LLVM's `llvm-cov` tool expects to see in coverage maps.
|
||||
///
|
||||
/// Returns `None` if the conversion failed for some reason. This shouldn't happen,
|
||||
/// but it's hard to rule out entirely (especially in the presence of complex macros
|
||||
/// or other expansions), and if it does happen then skipping a span or function is
|
||||
/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
|
||||
pub(crate) fn make_coverage_span(
|
||||
file_id: LocalFileId,
|
||||
source_map: &SourceMap,
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
file: &SourceFile,
|
||||
span: Span,
|
||||
) -> Option<ffi::CoverageSpan> {
|
||||
let span = ensure_non_empty_span(source_map, fn_cov_info, span)?;
|
||||
|
||||
let lo = span.lo();
|
||||
let hi = span.hi();
|
||||
|
||||
// Column numbers need to be in bytes, so we can't use the more convenient
|
||||
// `SourceMap` methods for looking up file coordinates.
|
||||
let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
|
||||
let rpos = file.relative_position(pos);
|
||||
let line_index = file.lookup_line(rpos)?;
|
||||
let line_start = file.lines()[line_index];
|
||||
// Line numbers and column numbers are 1-based, so add 1 to each.
|
||||
Some((line_index + 1, (rpos - line_start).to_usize() + 1))
|
||||
};
|
||||
|
||||
let (mut start_line, start_col) = line_and_byte_column(lo)?;
|
||||
let (mut end_line, end_col) = line_and_byte_column(hi)?;
|
||||
|
||||
// Apply an offset so that code in doctests has correct line numbers.
|
||||
// FIXME(#79417): Currently we have no way to offset doctest _columns_.
|
||||
start_line = source_map.doctest_offset_line(&file.name, start_line);
|
||||
end_line = source_map.doctest_offset_line(&file.name, end_line);
|
||||
|
||||
check_coverage_span(ffi::CoverageSpan {
|
||||
file_id: file_id.as_u32(),
|
||||
start_line: start_line as u32,
|
||||
start_col: start_col as u32,
|
||||
end_line: end_line as u32,
|
||||
end_col: end_col as u32,
|
||||
})
|
||||
}
|
||||
|
||||
fn ensure_non_empty_span(
|
||||
source_map: &SourceMap,
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
span: Span,
|
||||
) -> Option<Span> {
|
||||
if !span.is_empty() {
|
||||
return Some(span);
|
||||
}
|
||||
|
||||
let lo = span.lo();
|
||||
let hi = span.hi();
|
||||
|
||||
// The span is empty, so try to expand it to cover an adjacent '{' or '}',
|
||||
// but only within the bounds of the body span.
|
||||
let try_next = hi < fn_cov_info.body_span.hi();
|
||||
let try_prev = fn_cov_info.body_span.lo() < lo;
|
||||
if !(try_next || try_prev) {
|
||||
return None;
|
||||
}
|
||||
|
||||
source_map
|
||||
.span_to_source(span, |src, start, end| try {
|
||||
// We're only checking for specific ASCII characters, so we don't
|
||||
// have to worry about multi-byte code points.
|
||||
if try_next && src.as_bytes()[end] == b'{' {
|
||||
Some(span.with_hi(hi + BytePos(1)))
|
||||
} else if try_prev && src.as_bytes()[start - 1] == b'}' {
|
||||
Some(span.with_lo(lo - BytePos(1)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok()?
|
||||
}
|
||||
|
||||
/// If `llvm-cov` sees a source region that is improperly ordered (end < start),
|
||||
/// it will immediately exit with a fatal error. To prevent that from happening,
|
||||
/// discard regions that are improperly ordered, or might be interpreted in a
|
||||
/// way that makes them improperly ordered.
|
||||
fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option<ffi::CoverageSpan> {
|
||||
let ffi::CoverageSpan { file_id: _, start_line, start_col, end_line, end_col } = cov_span;
|
||||
|
||||
// Line/column coordinates are supposed to be 1-based. If we ever emit
|
||||
// coordinates of 0, `llvm-cov` might misinterpret them.
|
||||
let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
|
||||
// Coverage mappings use the high bit of `end_col` to indicate that a
|
||||
// region is actually a "gap" region, so make sure it's unset.
|
||||
let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
|
||||
// If a region is improperly ordered (end < start), `llvm-cov` will exit
|
||||
// with a fatal error, which is inconvenient for users and hard to debug.
|
||||
let is_ordered = (start_line, start_col) <= (end_line, end_col);
|
||||
|
||||
if all_nonzero && end_col_has_high_bit_unset && is_ordered {
|
||||
Some(cov_span)
|
||||
} else {
|
||||
debug!(
|
||||
?cov_span,
|
||||
?all_nonzero,
|
||||
?end_col_has_high_bit_unset,
|
||||
?is_ordered,
|
||||
"Skipping source region that would be misinterpreted or rejected by LLVM"
|
||||
);
|
||||
// If this happens in a debug build, ICE to make it easier to notice.
|
||||
debug_assert!(false, "Improper source region: {cov_span:?}");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(try_blocks)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -2460,4 +2460,7 @@ unsafe extern "C" {
|
|||
pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool;
|
||||
|
||||
pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool;
|
||||
|
||||
pub fn LLVMRustSetNoSanitizeAddress(Global: &Value);
|
||||
pub fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1117,14 +1117,14 @@ fn link_natively(
|
|||
let stripcmd = "rust-objcopy";
|
||||
match (strip, crate_type) {
|
||||
(Strip::Debuginfo, _) => {
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-S"])
|
||||
}
|
||||
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
|
||||
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-x"])
|
||||
}
|
||||
(Strip::Symbols, _) => {
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, None)
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[])
|
||||
}
|
||||
(Strip::None, _) => {}
|
||||
}
|
||||
|
|
@ -1141,7 +1141,7 @@ fn link_natively(
|
|||
match strip {
|
||||
// Always preserve the symbol table (-x).
|
||||
Strip::Debuginfo => {
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-x"])
|
||||
}
|
||||
// Strip::Symbols is handled via the --strip-all linker option.
|
||||
Strip::Symbols => {}
|
||||
|
|
@ -1158,11 +1158,15 @@ fn link_natively(
|
|||
match strip {
|
||||
Strip::Debuginfo => {
|
||||
// FIXME: AIX's strip utility only offers option to strip line number information.
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-l"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[
|
||||
"-X32_64", "-l",
|
||||
])
|
||||
}
|
||||
Strip::Symbols => {
|
||||
// Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-r"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[
|
||||
"-X32_64", "-r",
|
||||
])
|
||||
}
|
||||
Strip::None => {}
|
||||
}
|
||||
|
|
@ -1181,12 +1185,10 @@ fn strip_symbols_with_external_utility(
|
|||
sess: &Session,
|
||||
util: &str,
|
||||
out_filename: &Path,
|
||||
option: Option<&str>,
|
||||
options: &[&str],
|
||||
) {
|
||||
let mut cmd = Command::new(util);
|
||||
if let Some(option) = option {
|
||||
cmd.arg(option);
|
||||
}
|
||||
cmd.args(options);
|
||||
|
||||
let mut new_path = sess.get_tools_search_paths(false);
|
||||
if let Some(path) = env::var_os("PATH") {
|
||||
|
|
|
|||
|
|
@ -432,11 +432,9 @@ struct CompiledModules {
|
|||
|
||||
fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool {
|
||||
let sess = tcx.sess;
|
||||
let requested_for_rlib = sess.opts.cg.embed_bitcode
|
||||
sess.opts.cg.embed_bitcode
|
||||
&& tcx.crate_types().contains(&CrateType::Rlib)
|
||||
&& sess.opts.output_types.contains_key(&OutputType::Exe);
|
||||
let forced_by_target = sess.target.forces_embed_bitcode;
|
||||
requested_for_rlib || forced_by_target
|
||||
&& sess.opts.output_types.contains_key(&OutputType::Exe)
|
||||
}
|
||||
|
||||
fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool {
|
||||
|
|
|
|||
|
|
@ -576,9 +576,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`.
|
||||
//
|
||||
// At this point, `unsafe` has already been checked and `#[target_feature]` only affects codegen.
|
||||
// Emitting both `#[inline(always)]` and `#[target_feature]` can potentially result in an
|
||||
// ICE, because LLVM errors when the function fails to be inlined due to a target feature
|
||||
// mismatch.
|
||||
// Due to LLVM limitations, emitting both `#[inline(always)]` and `#[target_feature]` is *unsound*:
|
||||
// the function may be inlined into a caller with fewer target features. Also see
|
||||
// <https://github.com/rust-lang/rust/issues/116573>.
|
||||
//
|
||||
// Using `#[inline(always)]` implies that this closure will most likely be inlined into
|
||||
// its parent function, which effectively inherits the features anyway. Boxing this closure
|
||||
|
|
|
|||
|
|
@ -18,13 +18,12 @@ use rustc_middle::span_bug;
|
|||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_mir_dataflow::impls::{MaybeStorageLive, always_storage_live_locals};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_trait_selection::traits::{
|
||||
Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use super::ops::{self, NonConstOp, Status};
|
||||
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||
|
|
@ -47,7 +46,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
|
||||
///
|
||||
/// Only updates the cursor if absolutely necessary
|
||||
fn needs_drop(
|
||||
pub(crate) fn needs_drop(
|
||||
&mut self,
|
||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
||||
local: Local,
|
||||
|
|
@ -421,6 +420,43 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn check_drop_terminator(
|
||||
&mut self,
|
||||
dropped_place: Place<'tcx>,
|
||||
location: Location,
|
||||
terminator_span: Span,
|
||||
) {
|
||||
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
|
||||
|
||||
let needs_drop = if let Some(local) = dropped_place.as_local() {
|
||||
self.qualifs.needs_drop(self.ccx, local, location)
|
||||
} else {
|
||||
qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
|
||||
};
|
||||
// If this type doesn't need a drop at all, then there's nothing to enforce.
|
||||
if !needs_drop {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut err_span = self.span;
|
||||
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
|
||||
// Use the span where the local was declared as the span of the drop error.
|
||||
err_span = self.body.local_decls[local].source_info.span;
|
||||
self.qualifs.needs_non_const_drop(self.ccx, local, location)
|
||||
} else {
|
||||
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
|
||||
};
|
||||
|
||||
self.check_op_spanned(
|
||||
ops::LiveDrop {
|
||||
dropped_at: terminator_span,
|
||||
dropped_ty: ty_of_dropped_place,
|
||||
needs_non_const_drop,
|
||||
},
|
||||
err_span,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
|
|
@ -866,35 +902,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut err_span = self.span;
|
||||
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
|
||||
|
||||
let ty_needs_non_const_drop =
|
||||
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
|
||||
|
||||
debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
|
||||
|
||||
if !ty_needs_non_const_drop {
|
||||
return;
|
||||
}
|
||||
|
||||
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
|
||||
// Use the span where the local was declared as the span of the drop error.
|
||||
err_span = self.body.local_decls[local].source_info.span;
|
||||
self.qualifs.needs_non_const_drop(self.ccx, local, location)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if needs_non_const_drop {
|
||||
self.check_op_spanned(
|
||||
ops::LiveDrop {
|
||||
dropped_at: Some(terminator.source_info.span),
|
||||
dropped_ty: ty_of_dropped_place,
|
||||
},
|
||||
err_span,
|
||||
);
|
||||
}
|
||||
self.check_drop_terminator(*dropped_place, location, terminator.source_info.span);
|
||||
}
|
||||
|
||||
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
|
||||
|
|
|
|||
|
|
@ -459,17 +459,43 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LiveDrop<'tcx> {
|
||||
pub dropped_at: Option<Span>,
|
||||
pub dropped_at: Span,
|
||||
pub dropped_ty: Ty<'tcx>,
|
||||
pub needs_non_const_drop: bool,
|
||||
}
|
||||
impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if self.needs_non_const_drop {
|
||||
Status::Forbidden
|
||||
} else {
|
||||
Status::Unstable {
|
||||
gate: sym::const_destruct,
|
||||
gate_already_checked: false,
|
||||
safe_to_expose_on_stable: false,
|
||||
is_function_call: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::LiveDrop {
|
||||
span,
|
||||
dropped_ty: self.dropped_ty,
|
||||
kind: ccx.const_kind(),
|
||||
dropped_at: self.dropped_at,
|
||||
})
|
||||
if self.needs_non_const_drop {
|
||||
ccx.dcx().create_err(errors::LiveDrop {
|
||||
span,
|
||||
dropped_ty: self.dropped_ty,
|
||||
kind: ccx.const_kind(),
|
||||
dropped_at: self.dropped_at,
|
||||
})
|
||||
} else {
|
||||
ccx.tcx.sess.create_feature_err(
|
||||
errors::LiveDrop {
|
||||
span,
|
||||
dropped_ty: self.dropped_ty,
|
||||
kind: ccx.const_kind(),
|
||||
dropped_at: self.dropped_at,
|
||||
},
|
||||
sym::const_destruct,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::symbol::sym;
|
||||
use tracing::trace;
|
||||
|
||||
use super::ConstCx;
|
||||
use super::check::Qualifs;
|
||||
use super::ops::{self, NonConstOp};
|
||||
use super::qualifs::{NeedsNonConstDrop, Qualif};
|
||||
use crate::check_consts::check::Checker;
|
||||
use crate::check_consts::rustc_allow_const_fn_unstable;
|
||||
|
||||
/// Returns `true` if we should use the more precise live drop checker that runs after drop
|
||||
|
|
@ -45,29 +42,16 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
|
||||
// I know it's not great to be creating a new const checker, but I'd
|
||||
// rather use it so we can deduplicate the error emitting logic that
|
||||
// it contains.
|
||||
let mut visitor = CheckLiveDrops { checker: Checker::new(&ccx) };
|
||||
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
|
||||
struct CheckLiveDrops<'mir, 'tcx> {
|
||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
||||
qualifs: Qualifs<'mir, 'tcx>,
|
||||
}
|
||||
|
||||
// So we can access `body` and `tcx`.
|
||||
impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
|
||||
type Target = ConstCx<'mir, 'tcx>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.ccx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> CheckLiveDrops<'_, 'tcx> {
|
||||
fn check_live_drop(&self, span: Span, dropped_ty: Ty<'tcx>) {
|
||||
ops::LiveDrop { dropped_at: None, dropped_ty }.build_error(self.ccx, span).emit();
|
||||
}
|
||||
checker: Checker<'mir, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
||||
|
|
@ -87,28 +71,11 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
|||
|
||||
match &terminator.kind {
|
||||
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
|
||||
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
|
||||
|
||||
if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
|
||||
// Instead of throwing a bug, we just return here. This is because we have to
|
||||
// run custom `const Drop` impls.
|
||||
return;
|
||||
}
|
||||
|
||||
if dropped_place.is_indirect() {
|
||||
self.check_live_drop(terminator.source_info.span, dropped_ty);
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop elaboration is not precise enough to accept code like
|
||||
// `tests/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
|
||||
// initialized with `None` and never changed, it still emits drop glue.
|
||||
// Hence we additionally check the qualifs here to allow more code to pass.
|
||||
if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
|
||||
// Use the span where the dropped local was declared for the error.
|
||||
let span = self.body.local_decls[dropped_place.local].source_info.span;
|
||||
self.check_live_drop(span, dropped_ty);
|
||||
}
|
||||
self.checker.check_drop_terminator(
|
||||
*dropped_place,
|
||||
location,
|
||||
terminator.source_info.span,
|
||||
);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::UnwindTerminate(_)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
//!
|
||||
//! See the `Qualif` trait for more info.
|
||||
|
||||
// FIXME(const_trait_impl): This API should be really reworked. It's dangerously general for
|
||||
// having basically only two use-cases that act in different ways.
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
|
||||
use rustc_middle::ty::{self, AdtDef, Ty};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use tracing::instrument;
|
||||
|
|
@ -59,26 +62,12 @@ pub trait Qualif {
|
|||
/// It also determines the `Qualif`s for primitive types.
|
||||
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool;
|
||||
|
||||
/// Returns `true` if this `Qualif` is inherent to the given struct or enum.
|
||||
/// Returns `true` if the `Qualif` is structural in an ADT's fields, i.e. if we may
|
||||
/// recurse into an operand *value* to determine whether it has this `Qualif`.
|
||||
///
|
||||
/// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes
|
||||
/// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always*
|
||||
/// have a certain `Qualif`, regardless of whether their fields have it. For example, a type
|
||||
/// with a custom `Drop` impl is inherently `NeedsDrop`.
|
||||
///
|
||||
/// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound.
|
||||
fn in_adt_inherently<'tcx>(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
adt: AdtDef<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
/// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
|
||||
/// the pointer/reference qualifies if and only if the pointee qualifies.
|
||||
///
|
||||
/// (This is currently `false` for all our instances, but that may change in the future. Also,
|
||||
/// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.)
|
||||
fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool;
|
||||
/// If this returns false, `in_any_value_of_ty` will be invoked to determine the
|
||||
/// final qualif for this ADT.
|
||||
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool;
|
||||
}
|
||||
|
||||
/// Constant containing interior mutability (`UnsafeCell<T>`).
|
||||
|
|
@ -101,6 +90,11 @@ impl Qualif for HasMutInterior {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Avoid selecting for `UnsafeCell` either.
|
||||
if ty.ty_adt_def().is_some_and(|adt| adt.is_unsafe_cell()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We do not use `ty.is_freeze` here, because that requires revealing opaque types, which
|
||||
// requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
|
||||
// Instead we invoke an obligation context manually, and provide the opaque type inference settings
|
||||
|
|
@ -129,18 +123,10 @@ impl Qualif for HasMutInterior {
|
|||
!errors.is_empty()
|
||||
}
|
||||
|
||||
fn in_adt_inherently<'tcx>(
|
||||
_cx: &ConstCx<'_, 'tcx>,
|
||||
adt: AdtDef<'tcx>,
|
||||
_: GenericArgsRef<'tcx>,
|
||||
) -> bool {
|
||||
fn is_structural_in_adt_value<'tcx>(_cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
|
||||
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
|
||||
// It arises structurally for all other types.
|
||||
adt.is_unsafe_cell()
|
||||
}
|
||||
|
||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
||||
false
|
||||
!adt.is_unsafe_cell()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +140,7 @@ pub struct NeedsDrop;
|
|||
impl Qualif for NeedsDrop {
|
||||
const ANALYSIS_NAME: &'static str = "flow_needs_drop";
|
||||
const IS_CLEARED_ON_MOVE: bool = true;
|
||||
const ALLOW_PROMOTED: bool = true;
|
||||
|
||||
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
|
||||
qualifs.needs_drop
|
||||
|
|
@ -163,16 +150,8 @@ impl Qualif for NeedsDrop {
|
|||
ty.needs_drop(cx.tcx, cx.typing_env)
|
||||
}
|
||||
|
||||
fn in_adt_inherently<'tcx>(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
adt: AdtDef<'tcx>,
|
||||
_: GenericArgsRef<'tcx>,
|
||||
) -> bool {
|
||||
adt.has_dtor(cx.tcx)
|
||||
}
|
||||
|
||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
||||
false
|
||||
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
|
||||
!adt.has_dtor(cx.tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -191,25 +170,46 @@ impl Qualif for NeedsNonConstDrop {
|
|||
|
||||
#[instrument(level = "trace", skip(cx), ret)]
|
||||
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
// Avoid selecting for simple cases, such as builtin types.
|
||||
if ty::util::is_trivially_const_drop(ty) {
|
||||
// If this doesn't need drop at all, then don't select `~const Destruct`.
|
||||
if !ty.needs_drop(cx.tcx, cx.typing_env) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME(const_trait_impl): Reimplement const drop checking.
|
||||
NeedsDrop::in_any_value_of_ty(cx, ty)
|
||||
// We check that the type is `~const Destruct` since that will verify that
|
||||
// the type is both `~const Drop` (if a drop impl exists for the adt), *and*
|
||||
// that the components of this type are also `~const Destruct`. This
|
||||
// amounts to verifying that there are no values in this ADT that may have
|
||||
// a non-const drop.
|
||||
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
|
||||
let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligation(Obligation::new(
|
||||
cx.tcx,
|
||||
ObligationCause::misc(cx.body.span, cx.def_id()),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::TraitRef::new(cx.tcx, destruct_def_id, [ty]))
|
||||
.to_host_effect_clause(cx.tcx, match cx.const_kind() {
|
||||
rustc_hir::ConstContext::ConstFn => ty::BoundConstness::Maybe,
|
||||
rustc_hir::ConstContext::Static(_) | rustc_hir::ConstContext::Const { .. } => {
|
||||
ty::BoundConstness::Const
|
||||
}
|
||||
}),
|
||||
));
|
||||
!ocx.select_all_or_error().is_empty()
|
||||
}
|
||||
|
||||
fn in_adt_inherently<'tcx>(
|
||||
cx: &ConstCx<'_, 'tcx>,
|
||||
adt: AdtDef<'tcx>,
|
||||
_: GenericArgsRef<'tcx>,
|
||||
) -> bool {
|
||||
adt.has_non_const_dtor(cx.tcx)
|
||||
}
|
||||
|
||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
||||
false
|
||||
fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
|
||||
// As soon as an ADT has a destructor, then the drop becomes non-structural
|
||||
// in its value since:
|
||||
// 1. The destructor may have `~const` bounds which are not present on the type.
|
||||
// Someone needs to check that those are satisfied.
|
||||
// While this could be instead satisfied by checking that the `~const Drop`
|
||||
// impl holds (i.e. replicating part of the `in_any_value_of_ty` logic above),
|
||||
// even in this case, we have another problem, which is,
|
||||
// 2. The destructor may *modify* the operand being dropped, so even if we
|
||||
// did recurse on the components of the operand, we may not be even dropping
|
||||
// the same values that were present before the custom destructor was invoked.
|
||||
!adt.has_dtor(cx.tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -261,14 +261,15 @@ where
|
|||
Rvalue::Aggregate(kind, operands) => {
|
||||
// Return early if we know that the struct or enum being constructed is always
|
||||
// qualified.
|
||||
if let AggregateKind::Adt(adt_did, _, args, ..) = **kind {
|
||||
if let AggregateKind::Adt(adt_did, ..) = **kind {
|
||||
let def = cx.tcx.adt_def(adt_did);
|
||||
if Q::in_adt_inherently(cx, def, args) {
|
||||
return true;
|
||||
}
|
||||
// Don't do any value-based reasoning for unions.
|
||||
if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
|
||||
return true;
|
||||
// Also, if the ADT is not structural in its fields,
|
||||
// then we cannot recurse on its fields. Instead,
|
||||
// we fall back to checking the qualif for *any* value
|
||||
// of the ADT.
|
||||
if def.is_union() || !Q::is_structural_in_adt_value(cx, def) {
|
||||
return Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +306,11 @@ where
|
|||
return false;
|
||||
}
|
||||
|
||||
if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) {
|
||||
// `Deref` currently unconditionally "qualifies" if `in_any_value_of_ty` returns true,
|
||||
// i.e., we treat all qualifs as non-structural for deref projections. Generally,
|
||||
// we can say very little about `*ptr` even if we know that `ptr` satisfies all
|
||||
// sorts of properties.
|
||||
if matches!(elem, ProjectionElem::Deref) {
|
||||
// We have to assume that this qualifies.
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ pub struct LiveDrop<'tcx> {
|
|||
pub kind: ConstContext,
|
||||
pub dropped_ty: Ty<'tcx>,
|
||||
#[label(const_eval_dropped_at_label)]
|
||||
pub dropped_at: Option<Span>,
|
||||
pub dropped_at: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, mir};
|
||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||
use rustc_mir_dataflow::impls::always_storage_live_locals;
|
||||
use rustc_span::Span;
|
||||
use tracing::{info_span, instrument, trace};
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,9 @@ pub trait Callbacks {
|
|||
/// Called after parsing the crate root. Submodules are not yet parsed when
|
||||
/// this callback is called. Return value instructs the compiler whether to
|
||||
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
|
||||
#[deprecated = "This callback will likely be removed or stop giving access \
|
||||
to the TyCtxt in the future. Use either the after_expansion \
|
||||
or the after_analysis callback instead."]
|
||||
fn after_crate_root_parsing<'tcx>(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
|
|
@ -181,7 +184,7 @@ pub trait Callbacks {
|
|||
fn after_analysis<'tcx>(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
_queries: &'tcx Queries<'tcx>,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> Compilation {
|
||||
Compilation::Continue
|
||||
}
|
||||
|
|
@ -335,19 +338,12 @@ fn run_compiler(
|
|||
expanded_args: args,
|
||||
};
|
||||
|
||||
let has_input = match make_input(&default_early_dcx, &matches.free) {
|
||||
Err(reported) => return Err(reported),
|
||||
Ok(Some(input)) => {
|
||||
let has_input = match make_input(&default_early_dcx, &matches.free)? {
|
||||
Some(input) => {
|
||||
config.input = input;
|
||||
true // has input: normal compilation
|
||||
}
|
||||
Ok(None) => match matches.free.as_slice() {
|
||||
[] => false, // no input: we will exit early
|
||||
[_] => panic!("make_input should have provided valid inputs"),
|
||||
[fst, snd, ..] => default_early_dcx.early_fatal(format!(
|
||||
"multiple input filenames provided (first two filenames are `{fst}` and `{snd}`)"
|
||||
)),
|
||||
},
|
||||
None => false, // no input: we will exit early
|
||||
};
|
||||
|
||||
drop(default_early_dcx);
|
||||
|
|
@ -405,10 +401,6 @@ fn run_compiler(
|
|||
queries.global_ctxt()?.enter(|tcx| {
|
||||
tcx.ensure().early_lint_checks(());
|
||||
pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx });
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
queries.global_ctxt()?.enter(|tcx| {
|
||||
passes::write_dep_info(tcx);
|
||||
});
|
||||
} else {
|
||||
|
|
@ -421,6 +413,7 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
|
@ -442,25 +435,23 @@ fn run_compiler(
|
|||
|
||||
queries.global_ctxt()?.enter(|tcx| {
|
||||
passes::write_dep_info(tcx);
|
||||
});
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
return early_exit();
|
||||
}
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.no_analysis {
|
||||
return early_exit();
|
||||
}
|
||||
if sess.opts.unstable_opts.no_analysis {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
|
||||
tcx.analysis(())?;
|
||||
|
||||
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt()?.enter(|tcx| {
|
||||
Ok(Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)?))
|
||||
})
|
||||
})?;
|
||||
|
|
@ -472,10 +463,6 @@ fn run_compiler(
|
|||
linker.link(sess, codegen_backend)?
|
||||
}
|
||||
|
||||
if let Some(fuel) = sess.opts.unstable_opts.print_fuel.as_deref() {
|
||||
eprintln!("Fuel used by {}: {}", fuel, sess.print_fuel.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
@ -513,37 +500,40 @@ fn make_input(
|
|||
early_dcx: &EarlyDiagCtxt,
|
||||
free_matches: &[String],
|
||||
) -> Result<Option<Input>, ErrorGuaranteed> {
|
||||
let [input_file] = free_matches else { return Ok(None) };
|
||||
match free_matches {
|
||||
[] => Ok(None), // no input: we will exit early,
|
||||
[ifile] if ifile == "-" => {
|
||||
// read from stdin as `Input::Str`
|
||||
let mut input = String::new();
|
||||
if io::stdin().read_to_string(&mut input).is_err() {
|
||||
// Immediately stop compilation if there was an issue reading
|
||||
// the input (for example if the input stream is not UTF-8).
|
||||
let reported = early_dcx
|
||||
.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
if input_file != "-" {
|
||||
// Normal `Input::File`
|
||||
return Ok(Some(Input::File(PathBuf::from(input_file))));
|
||||
}
|
||||
|
||||
// read from stdin as `Input::Str`
|
||||
let mut input = String::new();
|
||||
if io::stdin().read_to_string(&mut input).is_err() {
|
||||
// Immediately stop compilation if there was an issue reading
|
||||
// the input (for example if the input stream is not UTF-8).
|
||||
let reported =
|
||||
early_dcx.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
|
||||
return Err(reported);
|
||||
}
|
||||
|
||||
let name = match env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
|
||||
Ok(path) => {
|
||||
let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
|
||||
"when UNSTABLE_RUSTDOC_TEST_PATH is set \
|
||||
let name = match env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
|
||||
Ok(path) => {
|
||||
let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
|
||||
"when UNSTABLE_RUSTDOC_TEST_PATH is set \
|
||||
UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
|
||||
);
|
||||
let line = isize::from_str_radix(&line, 10)
|
||||
.expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
|
||||
FileName::doc_test_source_code(PathBuf::from(path), line)
|
||||
}
|
||||
Err(_) => FileName::anon_source_code(&input),
|
||||
};
|
||||
);
|
||||
let line = isize::from_str_radix(&line, 10)
|
||||
.expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
|
||||
FileName::doc_test_source_code(PathBuf::from(path), line)
|
||||
}
|
||||
Err(_) => FileName::anon_source_code(&input),
|
||||
};
|
||||
|
||||
Ok(Some(Input::Str { name, input }))
|
||||
Ok(Some(Input::Str { name, input }))
|
||||
}
|
||||
[ifile] => Ok(Some(Input::File(PathBuf::from(ifile)))),
|
||||
[ifile1, ifile2, ..] => early_dcx.early_fatal(format!(
|
||||
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
|
||||
ifile1, ifile2
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to stop or continue compilation.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_ast::mut_visit::*;
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::{self as ast};
|
||||
use rustc_ast::{self as ast, Safety};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -173,6 +173,7 @@ pub(crate) fn placeholder(
|
|||
ty: ty(),
|
||||
vis,
|
||||
is_placeholder: true,
|
||||
safety: Safety::Default,
|
||||
}]),
|
||||
AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
|
||||
attrs: Default::default(),
|
||||
|
|
|
|||
|
|
@ -376,8 +376,12 @@ declare_features! (
|
|||
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
|
||||
/// Enables experimental inline assembly support for additional architectures.
|
||||
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
|
||||
/// Enables experimental register support in inline assembly.
|
||||
(unstable, asm_experimental_reg, "CURRENT_RUSTC_VERSION", Some(133416)),
|
||||
/// Allows using `label` operands in inline assembly.
|
||||
(unstable, asm_goto, "1.78.0", Some(119364)),
|
||||
/// Allows using `label` operands in inline assembly together with output operands.
|
||||
(unstable, asm_goto_with_outputs, "CURRENT_RUSTC_VERSION", Some(119364)),
|
||||
/// Allows the `may_unwind` option in inline assembly.
|
||||
(unstable, asm_unwind, "1.58.0", Some(93334)),
|
||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||
|
|
@ -426,6 +430,8 @@ declare_features! (
|
|||
(unstable, const_async_blocks, "1.53.0", Some(85368)),
|
||||
/// Allows `const || {}` closures in const contexts.
|
||||
(incomplete, const_closures, "1.68.0", Some(106003)),
|
||||
/// Allows using `~const Destruct` bounds and calling drop impls in const contexts.
|
||||
(unstable, const_destruct, "CURRENT_RUSTC_VERSION", Some(133214)),
|
||||
/// Allows `for _ in _` loops in const contexts.
|
||||
(unstable, const_for, "1.56.0", Some(87575)),
|
||||
/// Be more precise when looking for live drops in a const context.
|
||||
|
|
@ -627,6 +633,8 @@ declare_features! (
|
|||
/// Allows creation of instances of a struct by moving fields that have
|
||||
/// not changed from prior instances of the same struct (RFC #2528)
|
||||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||
/// Allows declaring fields `unsafe`.
|
||||
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
|
||||
/// Allows const generic parameters to be defined with types that
|
||||
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
|
||||
(incomplete, unsized_const_params, "1.82.0", Some(95174)),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_ast::util::parser::{AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_UNAMBIGUOUS};
|
||||
use rustc_ast::{
|
||||
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
|
||||
LitKind, TraitObjectSyntax, UintTy,
|
||||
|
|
@ -261,8 +261,6 @@ pub struct ConstArg<'hir> {
|
|||
#[stable_hasher(ignore)]
|
||||
pub hir_id: HirId,
|
||||
pub kind: ConstArgKind<'hir>,
|
||||
/// Indicates whether this comes from a `~const` desugaring.
|
||||
pub is_desugared_from_effects: bool,
|
||||
}
|
||||
|
||||
impl<'hir> ConstArg<'hir> {
|
||||
|
|
@ -462,14 +460,7 @@ impl<'hir> GenericArgs<'hir> {
|
|||
/// This function returns the number of type and const generic params.
|
||||
/// It should only be used for diagnostics.
|
||||
pub fn num_generic_params(&self) -> usize {
|
||||
self.args
|
||||
.iter()
|
||||
.filter(|arg| match arg {
|
||||
GenericArg::Lifetime(_)
|
||||
| GenericArg::Const(ConstArg { is_desugared_from_effects: true, .. }) => false,
|
||||
_ => true,
|
||||
})
|
||||
.count()
|
||||
self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count()
|
||||
}
|
||||
|
||||
/// The span encompassing the arguments and constraints[^1] inside the surrounding brackets.
|
||||
|
|
@ -690,8 +681,8 @@ impl<'hir> Generics<'hir> {
|
|||
if self.has_where_clause_predicates {
|
||||
self.predicates
|
||||
.iter()
|
||||
.rfind(|&p| p.in_where_clause())
|
||||
.map_or(end, |p| p.span())
|
||||
.rfind(|&p| p.kind.in_where_clause())
|
||||
.map_or(end, |p| p.span)
|
||||
.shrink_to_hi()
|
||||
.to(end)
|
||||
} else {
|
||||
|
|
@ -714,8 +705,10 @@ impl<'hir> Generics<'hir> {
|
|||
&self,
|
||||
param_def_id: LocalDefId,
|
||||
) -> impl Iterator<Item = &WhereBoundPredicate<'hir>> {
|
||||
self.predicates.iter().filter_map(move |pred| match pred {
|
||||
WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => {
|
||||
self.predicates.iter().filter_map(move |pred| match pred.kind {
|
||||
WherePredicateKind::BoundPredicate(bp)
|
||||
if bp.is_param_bound(param_def_id.to_def_id()) =>
|
||||
{
|
||||
Some(bp)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -726,8 +719,8 @@ impl<'hir> Generics<'hir> {
|
|||
&self,
|
||||
param_def_id: LocalDefId,
|
||||
) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
|
||||
self.predicates.iter().filter_map(move |pred| match pred {
|
||||
WherePredicate::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
|
||||
self.predicates.iter().filter_map(move |pred| match pred.kind {
|
||||
WherePredicateKind::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
|
@ -779,9 +772,9 @@ impl<'hir> Generics<'hir> {
|
|||
|
||||
pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
||||
let predicate = &self.predicates[pos];
|
||||
let span = predicate.span();
|
||||
let span = predicate.span;
|
||||
|
||||
if !predicate.in_where_clause() {
|
||||
if !predicate.kind.in_where_clause() {
|
||||
// <T: ?Sized, U>
|
||||
// ^^^^^^^^
|
||||
return span;
|
||||
|
|
@ -790,19 +783,19 @@ impl<'hir> Generics<'hir> {
|
|||
// We need to find out which comma to remove.
|
||||
if pos < self.predicates.len() - 1 {
|
||||
let next_pred = &self.predicates[pos + 1];
|
||||
if next_pred.in_where_clause() {
|
||||
if next_pred.kind.in_where_clause() {
|
||||
// where T: ?Sized, Foo: Bar,
|
||||
// ^^^^^^^^^^^
|
||||
return span.until(next_pred.span());
|
||||
return span.until(next_pred.span);
|
||||
}
|
||||
}
|
||||
|
||||
if pos > 0 {
|
||||
let prev_pred = &self.predicates[pos - 1];
|
||||
if prev_pred.in_where_clause() {
|
||||
if prev_pred.kind.in_where_clause() {
|
||||
// where Foo: Bar, T: ?Sized,
|
||||
// ^^^^^^^^^^^
|
||||
return prev_pred.span().shrink_to_hi().to(span);
|
||||
return prev_pred.span.shrink_to_hi().to(span);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -814,7 +807,7 @@ impl<'hir> Generics<'hir> {
|
|||
|
||||
pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) -> Span {
|
||||
let predicate = &self.predicates[predicate_pos];
|
||||
let bounds = predicate.bounds();
|
||||
let bounds = predicate.kind.bounds();
|
||||
|
||||
if bounds.len() == 1 {
|
||||
return self.span_for_predicate_removal(predicate_pos);
|
||||
|
|
@ -841,7 +834,15 @@ impl<'hir> Generics<'hir> {
|
|||
|
||||
/// A single predicate in a where-clause.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum WherePredicate<'hir> {
|
||||
pub struct WherePredicate<'hir> {
|
||||
pub hir_id: HirId,
|
||||
pub span: Span,
|
||||
pub kind: &'hir WherePredicateKind<'hir>,
|
||||
}
|
||||
|
||||
/// The kind of a single predicate in a where-clause.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum WherePredicateKind<'hir> {
|
||||
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
BoundPredicate(WhereBoundPredicate<'hir>),
|
||||
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
|
||||
|
|
@ -850,28 +851,20 @@ pub enum WherePredicate<'hir> {
|
|||
EqPredicate(WhereEqPredicate<'hir>),
|
||||
}
|
||||
|
||||
impl<'hir> WherePredicate<'hir> {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
WherePredicate::BoundPredicate(p) => p.span,
|
||||
WherePredicate::RegionPredicate(p) => p.span,
|
||||
WherePredicate::EqPredicate(p) => p.span,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> WherePredicateKind<'hir> {
|
||||
pub fn in_where_clause(&self) -> bool {
|
||||
match self {
|
||||
WherePredicate::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause,
|
||||
WherePredicate::RegionPredicate(p) => p.in_where_clause,
|
||||
WherePredicate::EqPredicate(_) => false,
|
||||
WherePredicateKind::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause,
|
||||
WherePredicateKind::RegionPredicate(p) => p.in_where_clause,
|
||||
WherePredicateKind::EqPredicate(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bounds(&self) -> GenericBounds<'hir> {
|
||||
match self {
|
||||
WherePredicate::BoundPredicate(p) => p.bounds,
|
||||
WherePredicate::RegionPredicate(p) => p.bounds,
|
||||
WherePredicate::EqPredicate(_) => &[],
|
||||
WherePredicateKind::BoundPredicate(p) => p.bounds,
|
||||
WherePredicateKind::RegionPredicate(p) => p.bounds,
|
||||
WherePredicateKind::EqPredicate(_) => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -886,8 +879,6 @@ pub enum PredicateOrigin {
|
|||
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct WhereBoundPredicate<'hir> {
|
||||
pub hir_id: HirId,
|
||||
pub span: Span,
|
||||
/// Origin of the predicate.
|
||||
pub origin: PredicateOrigin,
|
||||
/// Any generics from a `for` binding.
|
||||
|
|
@ -908,7 +899,6 @@ impl<'hir> WhereBoundPredicate<'hir> {
|
|||
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct WhereRegionPredicate<'hir> {
|
||||
pub span: Span,
|
||||
pub in_where_clause: bool,
|
||||
pub lifetime: &'hir Lifetime,
|
||||
pub bounds: GenericBounds<'hir>,
|
||||
|
|
@ -924,7 +914,6 @@ impl<'hir> WhereRegionPredicate<'hir> {
|
|||
/// An equality predicate (e.g., `T = int`); currently unsupported.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct WhereEqPredicate<'hir> {
|
||||
pub span: Span,
|
||||
pub lhs_ty: &'hir Ty<'hir>,
|
||||
pub rhs_ty: &'hir Ty<'hir>,
|
||||
}
|
||||
|
|
@ -1719,41 +1708,54 @@ pub struct Expr<'hir> {
|
|||
}
|
||||
|
||||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
pub fn precedence(&self) -> i8 {
|
||||
match self.kind {
|
||||
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
|
||||
ExprKind::Array(_) => ExprPrecedence::Array,
|
||||
ExprKind::Call(..) => ExprPrecedence::Call,
|
||||
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
|
||||
ExprKind::Tup(_) => ExprPrecedence::Tup,
|
||||
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
|
||||
ExprKind::Unary(..) => ExprPrecedence::Unary,
|
||||
ExprKind::Lit(_) => ExprPrecedence::Lit,
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
ExprKind::Closure { .. } => PREC_CLOSURE,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
|
||||
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::AddrOf(..)
|
||||
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
|
||||
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
|
||||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => PREC_PREFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Index(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::Lit(_)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::OffsetOf(..)
|
||||
| ExprKind::Path(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Err(_) => PREC_UNAMBIGUOUS,
|
||||
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
ExprKind::If(..) => ExprPrecedence::If,
|
||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||
ExprKind::Match(..) => ExprPrecedence::Match,
|
||||
ExprKind::Closure { .. } => ExprPrecedence::Closure,
|
||||
ExprKind::Block(..) => ExprPrecedence::Block,
|
||||
ExprKind::Assign(..) => ExprPrecedence::Assign,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
|
||||
ExprKind::Field(..) => ExprPrecedence::Field,
|
||||
ExprKind::Index(..) => ExprPrecedence::Index,
|
||||
ExprKind::Path(..) => ExprPrecedence::Path,
|
||||
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
|
||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => {
|
||||
ExprPrecedence::Mac
|
||||
}
|
||||
ExprKind::Err(_) => ExprPrecedence::Err,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3177,6 +3179,7 @@ pub struct FieldDef<'hir> {
|
|||
pub hir_id: HirId,
|
||||
pub def_id: LocalDefId,
|
||||
pub ty: &'hir Ty<'hir>,
|
||||
pub safety: Safety,
|
||||
}
|
||||
|
||||
impl FieldDef<'_> {
|
||||
|
|
@ -3797,7 +3800,7 @@ pub enum Node<'hir> {
|
|||
GenericParam(&'hir GenericParam<'hir>),
|
||||
Crate(&'hir Mod<'hir>),
|
||||
Infer(&'hir InferArg),
|
||||
WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>),
|
||||
WherePredicate(&'hir WherePredicate<'hir>),
|
||||
// FIXME: Merge into `Node::Infer`.
|
||||
ArrayLenInfer(&'hir InferArg),
|
||||
PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg),
|
||||
|
|
@ -3852,7 +3855,7 @@ impl<'hir> Node<'hir> {
|
|||
| Node::TraitRef(..)
|
||||
| Node::OpaqueTy(..)
|
||||
| Node::Infer(..)
|
||||
| Node::WhereBoundPredicate(..)
|
||||
| Node::WherePredicate(..)
|
||||
| Node::ArrayLenInfer(..)
|
||||
| Node::Synthetic
|
||||
| Node::Err(..) => None,
|
||||
|
|
|
|||
|
|
@ -961,30 +961,28 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
predicate: &'v WherePredicate<'v>,
|
||||
) -> V::Result {
|
||||
match *predicate {
|
||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||
hir_id,
|
||||
let &WherePredicate { hir_id, kind, span: _ } = predicate;
|
||||
try_visit!(visitor.visit_id(hir_id));
|
||||
match *kind {
|
||||
WherePredicateKind::BoundPredicate(WhereBoundPredicate {
|
||||
ref bounded_ty,
|
||||
bounds,
|
||||
bound_generic_params,
|
||||
origin: _,
|
||||
span: _,
|
||||
}) => {
|
||||
try_visit!(visitor.visit_id(hir_id));
|
||||
try_visit!(visitor.visit_ty(bounded_ty));
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_generic_param, bound_generic_params);
|
||||
}
|
||||
WherePredicate::RegionPredicate(WhereRegionPredicate {
|
||||
WherePredicateKind::RegionPredicate(WhereRegionPredicate {
|
||||
ref lifetime,
|
||||
bounds,
|
||||
span: _,
|
||||
in_where_clause: _,
|
||||
}) => {
|
||||
try_visit!(visitor.visit_lifetime(lifetime));
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span: _ }) => {
|
||||
WherePredicateKind::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty }) => {
|
||||
try_visit!(visitor.visit_ty(lhs_ty));
|
||||
try_visit!(visitor.visit_ty(rhs_ty));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,6 +253,13 @@ hir_analysis_invalid_union_field =
|
|||
hir_analysis_invalid_union_field_sugg =
|
||||
wrap the field type in `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_invalid_unsafe_field =
|
||||
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be unsafe
|
||||
.note = unsafe fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_invalid_unsafe_field_sugg =
|
||||
wrap the field type in `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
|
||||
.label = const parameter declared here
|
||||
|
||||
|
|
@ -424,6 +431,9 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is
|
|||
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
|
||||
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
|
||||
|
||||
hir_analysis_register_type_unstable =
|
||||
type `{$ty}` cannot be used with this register class in stable
|
||||
|
||||
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
|
||||
|
||||
hir_analysis_return_type_notation_equality_bound =
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
|
|||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::{Node, intravisit};
|
||||
use rustc_hir::{Node, Safety, intravisit};
|
||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{Obligation, ObligationCauseCode};
|
||||
use rustc_lint_defs::builtin::{
|
||||
|
|
@ -70,6 +70,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
check_transparent(tcx, def);
|
||||
check_packed(tcx, span, def);
|
||||
check_unsafe_fields(tcx, def_id);
|
||||
}
|
||||
|
||||
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
|
|
@ -81,38 +82,45 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
check_packed(tcx, span, def);
|
||||
}
|
||||
|
||||
fn allowed_union_or_unsafe_field<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
// We don't just accept all !needs_drop fields, due to semver concerns.
|
||||
let allowed = match ty.kind() {
|
||||
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
|
||||
ty::Tuple(tys) => {
|
||||
// allow tuples of allowed types
|
||||
tys.iter().all(|ty| allowed_union_or_unsafe_field(tcx, ty, typing_env, span))
|
||||
}
|
||||
ty::Array(elem, _len) => {
|
||||
// Like `Copy`, we do *not* special-case length 0.
|
||||
allowed_union_or_unsafe_field(tcx, *elem, typing_env, span)
|
||||
}
|
||||
_ => {
|
||||
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
|
||||
// also no need to report an error if the type is unresolved.
|
||||
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
||||
|| ty.is_copy_modulo_regions(tcx, typing_env)
|
||||
|| ty.references_error()
|
||||
}
|
||||
};
|
||||
if allowed && ty.needs_drop(tcx, typing_env) {
|
||||
// This should never happen. But we can get here e.g. in case of name resolution errors.
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(span, "we should never accept maybe-dropping union or unsafe fields");
|
||||
}
|
||||
allowed
|
||||
}
|
||||
|
||||
/// Check that the fields of the `union` do not need dropping.
|
||||
fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
|
||||
let item_type = tcx.type_of(item_def_id).instantiate_identity();
|
||||
if let ty::Adt(def, args) = item_type.kind() {
|
||||
assert!(def.is_union());
|
||||
|
||||
fn allowed_union_field<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
) -> bool {
|
||||
// We don't just accept all !needs_drop fields, due to semver concerns.
|
||||
match ty.kind() {
|
||||
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
|
||||
ty::Tuple(tys) => {
|
||||
// allow tuples of allowed types
|
||||
tys.iter().all(|ty| allowed_union_field(ty, tcx, typing_env))
|
||||
}
|
||||
ty::Array(elem, _len) => {
|
||||
// Like `Copy`, we do *not* special-case length 0.
|
||||
allowed_union_field(*elem, tcx, typing_env)
|
||||
}
|
||||
_ => {
|
||||
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
|
||||
// also no need to report an error if the type is unresolved.
|
||||
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
||||
|| ty.is_copy_modulo_regions(tcx, typing_env)
|
||||
|| ty.references_error()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
|
||||
for field in &def.non_enum_variant().fields {
|
||||
let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args))
|
||||
|
|
@ -121,7 +129,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
|||
continue;
|
||||
};
|
||||
|
||||
if !allowed_union_field(field_ty, tcx, typing_env) {
|
||||
if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) {
|
||||
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
|
||||
// We are currently checking the type this field came from, so it must be local.
|
||||
Some(Node::Field(field)) => (field.span, field.ty.span),
|
||||
|
|
@ -136,10 +144,6 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
|||
note: (),
|
||||
});
|
||||
return false;
|
||||
} else if field_ty.needs_drop(tcx, typing_env) {
|
||||
// This should never happen. But we can get here e.g. in case of name resolution errors.
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(span, "we should never accept maybe-dropping union fields");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -148,6 +152,41 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
|||
true
|
||||
}
|
||||
|
||||
/// Check that the unsafe fields do not need dropping.
|
||||
fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) {
|
||||
let span = tcx.def_span(item_def_id);
|
||||
let item_type = tcx.type_of(item_def_id).instantiate_identity();
|
||||
let ty::Adt(def, args) = item_type.kind() else {
|
||||
span_bug!(span, "structs/enums must be ty::Adt, but got {:?}", item_type.kind());
|
||||
};
|
||||
let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
|
||||
for field in def.all_fields() {
|
||||
if field.safety != Safety::Unsafe {
|
||||
continue;
|
||||
}
|
||||
let Ok(field_ty) = tcx.try_normalize_erasing_regions(typing_env, field.ty(tcx, args))
|
||||
else {
|
||||
tcx.dcx().span_delayed_bug(span, "could not normalize field type");
|
||||
continue;
|
||||
};
|
||||
|
||||
if !allowed_union_or_unsafe_field(tcx, field_ty, typing_env, span) {
|
||||
let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else {
|
||||
unreachable!("field has to correspond to hir field")
|
||||
};
|
||||
let ty_span = field.ty.span;
|
||||
tcx.dcx().emit_err(errors::InvalidUnsafeField {
|
||||
field_span: field.span,
|
||||
sugg: errors::InvalidUnsafeFieldSuggestion {
|
||||
lo: ty_span.shrink_to_lo(),
|
||||
hi: ty_span.shrink_to_hi(),
|
||||
},
|
||||
note: (),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that a `static` is inhabited.
|
||||
fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
// Make sure statics are inhabited.
|
||||
|
|
@ -1464,6 +1503,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
detect_discriminant_duplicate(tcx, def);
|
||||
check_transparent(tcx, def);
|
||||
check_unsafe_fields(tcx, def_id);
|
||||
}
|
||||
|
||||
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
|||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
|
||||
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
}
|
||||
|
||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds));
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
debug!(caller_bounds=?param_env.caller_bounds());
|
||||
|
||||
|
|
@ -508,7 +508,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
.into_iter()
|
||||
.chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args))
|
||||
.map(|(clause, _)| clause);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds));
|
||||
let param_env = traits::normalize_param_env_or_error(
|
||||
tcx,
|
||||
param_env,
|
||||
|
|
@ -1100,7 +1100,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
|||
// FIXME: we could potentially look at the impl's bounds to not point at bounds that
|
||||
// *are* present in the impl.
|
||||
for p in trait_generics.predicates {
|
||||
if let hir::WherePredicate::BoundPredicate(pred) = p {
|
||||
if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
|
||||
for b in pred.bounds {
|
||||
if let hir::GenericBound::Outlives(lt) = b {
|
||||
bounds_span.push(lt.ident.span);
|
||||
|
|
@ -1113,7 +1113,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
|
|||
{
|
||||
let mut impl_bounds = 0;
|
||||
for p in impl_generics.predicates {
|
||||
if let hir::WherePredicate::BoundPredicate(pred) = p {
|
||||
if let hir::WherePredicateKind::BoundPredicate(pred) = p.kind {
|
||||
for b in pred.bounds {
|
||||
if let hir::GenericBound::Outlives(_) = b {
|
||||
impl_bounds += 1;
|
||||
|
|
@ -1793,7 +1793,7 @@ fn compare_const_predicate_entailment<'tcx>(
|
|||
.map(|(predicate, _)| predicate),
|
||||
);
|
||||
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds));
|
||||
let param_env = traits::normalize_param_env_or_error(
|
||||
tcx,
|
||||
param_env,
|
||||
|
|
@ -1946,7 +1946,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
);
|
||||
}
|
||||
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds));
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
debug!(caller_bounds=?param_env.caller_bounds());
|
||||
|
||||
|
|
@ -2306,7 +2306,7 @@ fn param_env_with_gat_bounds<'tcx>(
|
|||
};
|
||||
}
|
||||
|
||||
ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
|
||||
ty::ParamEnv::new(tcx.mk_clauses(&predicates))
|
||||
}
|
||||
|
||||
/// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_infer::infer::TyCtxtInferExt;
|
|||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::{ObligationCause, Reveal};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, TypingMode,
|
||||
|
|
@ -134,7 +134,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||
.into_iter()
|
||||
.chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args))
|
||||
.map(|(clause, _)| clause);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds));
|
||||
let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy());
|
||||
|
||||
let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ use rustc_hir::{self as hir, LangItem};
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_target::asm::{
|
||||
InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
|
||||
};
|
||||
|
||||
use crate::errors::RegisterTypeUnstable;
|
||||
|
||||
pub struct InlineAsmCtxt<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
|
|
@ -218,17 +220,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
// Check the type against the list of types supported by the selected
|
||||
// register class.
|
||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
|
||||
let reg_class = reg.reg_class();
|
||||
let supported_tys = reg_class.supported_types(asm_arch);
|
||||
let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg);
|
||||
let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
|
||||
let msg = format!("type `{ty}` cannot be used with this register class");
|
||||
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
|
||||
let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect();
|
||||
err.note(format!(
|
||||
"register class `{}` supports these types: {}",
|
||||
reg_class.name(),
|
||||
supported_tys.join(", "),
|
||||
));
|
||||
let mut err = if !allow_experimental_reg
|
||||
&& reg_class.supported_types(asm_arch, true).iter().any(|&(t, _)| t == asm_ty)
|
||||
{
|
||||
self.tcx.sess.create_feature_err(
|
||||
RegisterTypeUnstable { span: expr.span, ty },
|
||||
sym::asm_experimental_reg,
|
||||
)
|
||||
} else {
|
||||
let msg = format!("type `{ty}` cannot be used with this register class");
|
||||
let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
|
||||
let supported_tys: Vec<_> =
|
||||
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
|
||||
err.note(format!(
|
||||
"register class `{}` supports these types: {}",
|
||||
reg_class.name(),
|
||||
supported_tys.join(", "),
|
||||
));
|
||||
err
|
||||
};
|
||||
if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) {
|
||||
err.help(format!("consider using the `{}` register class instead", suggest.name()));
|
||||
}
|
||||
|
|
@ -313,6 +327,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
self.tcx.dcx().delayed_bug("target architecture does not support asm");
|
||||
return;
|
||||
};
|
||||
let allow_experimental_reg = self.tcx.features().asm_experimental_reg();
|
||||
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
|
||||
// Validate register classes against currently enabled target
|
||||
// features. We check that at least one type is available for
|
||||
|
|
@ -352,7 +367,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
if let InlineAsmRegClass::Err = reg_class {
|
||||
continue;
|
||||
}
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch) {
|
||||
for &(_, feature) in reg_class.supported_types(asm_arch, allow_experimental_reg)
|
||||
{
|
||||
match feature {
|
||||
Some(feature) => {
|
||||
if target_features.contains(&feature) {
|
||||
|
|
|
|||
|
|
@ -604,7 +604,7 @@ fn augment_param_env<'tcx>(
|
|||
);
|
||||
// FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
|
||||
// i.e. traits::normalize_param_env_or_error
|
||||
ty::ParamEnv::new(bounds, param_env.reveal())
|
||||
ty::ParamEnv::new(bounds)
|
||||
}
|
||||
|
||||
/// We use the following trait as an example throughout this function.
|
||||
|
|
@ -1921,8 +1921,8 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
hir_generics
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|predicate| match predicate {
|
||||
hir::WherePredicate::BoundPredicate(predicate) => {
|
||||
.filter_map(|predicate| match predicate.kind {
|
||||
hir::WherePredicateKind::BoundPredicate(predicate) => {
|
||||
match icx.lower_ty(predicate.bounded_ty).kind() {
|
||||
ty::Param(data) => Some(Parameter(data.index)),
|
||||
_ => None,
|
||||
|
|
@ -2202,8 +2202,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
span = predicates
|
||||
.iter()
|
||||
// There seems to be no better way to find out which predicate we are in
|
||||
.find(|pred| pred.span().contains(obligation_span))
|
||||
.map(|pred| pred.span())
|
||||
.find(|pred| pred.span.contains(obligation_span))
|
||||
.map(|pred| pred.span)
|
||||
.unwrap_or(obligation_span);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1040,6 +1040,7 @@ fn lower_variant(
|
|||
did: f.def_id.to_def_id(),
|
||||
name: f.ident.name,
|
||||
vis: tcx.visibility(f.def_id),
|
||||
safety: f.safety,
|
||||
})
|
||||
.collect();
|
||||
let recovered = match def {
|
||||
|
|
|
|||
|
|
@ -238,11 +238,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
trace!(?predicates);
|
||||
// Add inline `<T: Foo>` bounds and bounds in the where clause.
|
||||
for predicate in hir_generics.predicates {
|
||||
match predicate {
|
||||
hir::WherePredicate::BoundPredicate(bound_pred) => {
|
||||
match predicate.kind {
|
||||
hir::WherePredicateKind::BoundPredicate(bound_pred) => {
|
||||
let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
|
||||
|
||||
let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
|
||||
let bound_vars = tcx.late_bound_vars(predicate.hir_id);
|
||||
// Keep the type around in a dummy predicate, in case of no bounds.
|
||||
// That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
|
||||
// is still checked for WF.
|
||||
|
|
@ -275,7 +275,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
predicates.extend(bounds.clauses());
|
||||
}
|
||||
|
||||
hir::WherePredicate::RegionPredicate(region_pred) => {
|
||||
hir::WherePredicateKind::RegionPredicate(region_pred) => {
|
||||
let r1 = icx
|
||||
.lowerer()
|
||||
.lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate);
|
||||
|
|
@ -298,7 +298,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
}))
|
||||
}
|
||||
|
||||
hir::WherePredicate::EqPredicate(..) => {
|
||||
hir::WherePredicateKind::EqPredicate(..) => {
|
||||
// FIXME(#20041)
|
||||
}
|
||||
}
|
||||
|
|
@ -881,7 +881,8 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
let mut bounds = Bounds::default();
|
||||
|
||||
for predicate in hir_generics.predicates {
|
||||
let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
|
||||
let hir_id = predicate.hir_id;
|
||||
let hir::WherePredicateKind::BoundPredicate(predicate) = predicate.kind else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -901,7 +902,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
|
||||
let bound_ty = self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty);
|
||||
|
||||
let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
|
||||
let bound_vars = self.tcx.late_bound_vars(hir_id);
|
||||
self.lowerer().lower_bounds(
|
||||
bound_ty,
|
||||
predicate.bounds,
|
||||
|
|
@ -974,10 +975,10 @@ pub(super) fn const_conditions<'tcx>(
|
|||
let mut bounds = Bounds::default();
|
||||
|
||||
for pred in generics.predicates {
|
||||
match pred {
|
||||
hir::WherePredicate::BoundPredicate(bound_pred) => {
|
||||
match pred.kind {
|
||||
hir::WherePredicateKind::BoundPredicate(bound_pred) => {
|
||||
let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);
|
||||
let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
|
||||
let bound_vars = tcx.late_bound_vars(pred.hir_id);
|
||||
icx.lowerer().lower_bounds(
|
||||
ty,
|
||||
bound_pred.bounds.iter(),
|
||||
|
|
|
|||
|
|
@ -936,9 +936,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>) {
|
||||
match predicate {
|
||||
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
hir_id,
|
||||
let hir_id = predicate.hir_id;
|
||||
match predicate.kind {
|
||||
&hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bounded_ty,
|
||||
bounds,
|
||||
bound_generic_params,
|
||||
|
|
@ -979,7 +979,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
walk_list!(this, visit_param_bound, bounds);
|
||||
})
|
||||
}
|
||||
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
&hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime,
|
||||
bounds,
|
||||
..
|
||||
|
|
@ -987,7 +987,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
self.visit_lifetime(lifetime);
|
||||
walk_list!(self, visit_param_bound, bounds);
|
||||
}
|
||||
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
|
||||
&hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty, rhs_ty, ..
|
||||
}) => {
|
||||
self.visit_ty(lhs_ty);
|
||||
self.visit_ty(rhs_ty);
|
||||
}
|
||||
|
|
@ -2073,7 +2075,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// bounds since we'll be emitting a hard error in HIR lowering, so this
|
||||
// is purely speculative.
|
||||
let one_bound = generics.predicates.iter().find_map(|predicate| {
|
||||
let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
|
||||
let hir::WherePredicateKind::BoundPredicate(predicate) = predicate.kind
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) =
|
||||
|
|
|
|||
|
|
@ -734,6 +734,17 @@ pub(crate) struct InvalidUnionField {
|
|||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_unsafe_field, code = E0740)]
|
||||
pub(crate) struct InvalidUnsafeField {
|
||||
#[primary_span]
|
||||
pub field_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: InvalidUnsafeFieldSuggestion,
|
||||
#[note]
|
||||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_on_non_rpitit)]
|
||||
pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
|
||||
|
|
@ -755,6 +766,18 @@ pub(crate) struct InvalidUnionFieldSuggestion {
|
|||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
hir_analysis_invalid_unsafe_field_sugg,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidUnsafeFieldSuggestion {
|
||||
#[suggestion_part(code = "std::mem::ManuallyDrop<")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = ">")]
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_equality_bound)]
|
||||
pub(crate) struct ReturnTypeNotationEqualityBound {
|
||||
|
|
@ -1685,3 +1708,11 @@ pub(crate) struct CmseEntryGeneric {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_register_type_unstable)]
|
||||
pub(crate) struct RegisterTypeUnstable<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
search_bounds(hir_bounds);
|
||||
if let Some((self_ty, where_clause)) = self_ty_where_predicates {
|
||||
for clause in where_clause {
|
||||
if let hir::WherePredicate::BoundPredicate(pred) = clause
|
||||
if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind
|
||||
&& pred.is_param_bound(self_ty.to_def_id())
|
||||
{
|
||||
search_bounds(pred.bounds);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
|
|||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::{
|
||||
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
|
||||
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
|
||||
TypeVisitableExt, Upcast,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
|
||||
|
|
@ -92,11 +93,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
||||
|
||||
// We don't support >1 principal
|
||||
if regular_traits.len() > 1 {
|
||||
let _ = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||
} else if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
|
||||
return Ty::new_error(tcx, reported);
|
||||
let guar = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// We don't support empty trait objects.
|
||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
// Don't create a dyn trait if we have errors in the principal.
|
||||
if let Err(guar) = trait_bounds.error_reported() {
|
||||
return Ty::new_error(tcx, guar);
|
||||
}
|
||||
|
||||
// Check that there are no gross dyn-compatibility violations;
|
||||
|
|
@ -126,7 +136,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
for (base_trait_ref, original_span) in regular_traits_refs_spans {
|
||||
let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
|
||||
for ClauseWithSupertraitSpan { pred, original_span, supertrait_span } in
|
||||
for ClauseWithSupertraitSpan { pred, supertrait_span } in
|
||||
traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
|
||||
.filter_only_self()
|
||||
{
|
||||
|
|
@ -194,7 +204,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
for def_ids in associated_types.values_mut() {
|
||||
for (projection_bound, span) in &projection_bounds {
|
||||
let def_id = projection_bound.projection_def_id();
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
def_ids.swap_remove(&def_id);
|
||||
if tcx.generics_require_sized_self(def_id) {
|
||||
tcx.emit_node_span_lint(
|
||||
|
|
|
|||
|
|
@ -727,7 +727,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let tcx = self.tcx();
|
||||
// FIXME: Marked `mut` so that we can replace the spans further below with a more
|
||||
// appropriate one, but this should be handled earlier in the span assignment.
|
||||
let mut associated_types: FxIndexMap<Span, Vec<_>> = associated_types
|
||||
let associated_types: FxIndexMap<Span, Vec<_>> = associated_types
|
||||
.into_iter()
|
||||
.map(|(span, def_ids)| {
|
||||
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
|
||||
|
|
@ -769,39 +769,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::Node::Expr(_) | hir::Node::Pat(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
match bound.trait_ref.path.segments {
|
||||
// FIXME: `trait_ref.path.span` can point to a full path with multiple
|
||||
// segments, even though `trait_ref.path.segments` is of length `1`. Work
|
||||
// around that bug here, even though it should be fixed elsewhere.
|
||||
// This would otherwise cause an invalid suggestion. For an example, look at
|
||||
// `tests/ui/issues/issue-28344.rs` where instead of the following:
|
||||
//
|
||||
// error[E0191]: the value of the associated type `Output`
|
||||
// (from trait `std::ops::BitXor`) must be specified
|
||||
// --> $DIR/issue-28344.rs:4:17
|
||||
// |
|
||||
// LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
|
||||
// | ^^^^^^ help: specify the associated type:
|
||||
// | `BitXor<Output = Type>`
|
||||
//
|
||||
// we would output:
|
||||
//
|
||||
// error[E0191]: the value of the associated type `Output`
|
||||
// (from trait `std::ops::BitXor`) must be specified
|
||||
// --> $DIR/issue-28344.rs:4:17
|
||||
// |
|
||||
// LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
|
||||
// | ^^^^^^^^^^^^^ help: specify the associated type:
|
||||
// | `BitXor::bitor<Output = Type>`
|
||||
[segment] if segment.args.is_none() => {
|
||||
trait_bound_spans = vec![segment.ident.span];
|
||||
associated_types = associated_types
|
||||
.into_values()
|
||||
.map(|items| (segment.ident.span, items))
|
||||
.collect();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// We get all the associated items that _are_ set,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::specialization_graph::Node;
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -210,13 +211,7 @@ fn get_impl_args(
|
|||
impl1_def_id.to_def_id(),
|
||||
impl1_args,
|
||||
impl2_node,
|
||||
|_, span| {
|
||||
traits::ObligationCause::new(
|
||||
impl1_span,
|
||||
impl1_def_id,
|
||||
traits::ObligationCauseCode::WhereClause(impl2_node.def_id(), span),
|
||||
)
|
||||
},
|
||||
&ObligationCause::misc(impl1_span, impl1_def_id),
|
||||
);
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
|
|
|
|||
|
|
@ -117,11 +117,7 @@ impl<'a> State<'a> {
|
|||
Node::Ctor(..) => panic!("cannot print isolated Ctor"),
|
||||
Node::LetStmt(a) => self.print_local_decl(a),
|
||||
Node::Crate(..) => panic!("cannot print Crate"),
|
||||
Node::WhereBoundPredicate(pred) => {
|
||||
self.print_formal_generic_params(pred.bound_generic_params);
|
||||
self.print_type(pred.bounded_ty);
|
||||
self.print_bounds(":", pred.bounds);
|
||||
}
|
||||
Node::WherePredicate(pred) => self.print_where_predicate(pred),
|
||||
Node::ArrayLenInfer(_) => self.word("_"),
|
||||
Node::Synthetic => unreachable!(),
|
||||
Node::Err(_) => self.word("/*ERROR*/"),
|
||||
|
|
@ -1015,7 +1011,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < prec)
|
||||
}
|
||||
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
|
|
@ -1049,7 +1045,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
let npals = || parser::needs_par_as_let_scrutinee(init.precedence().order());
|
||||
let npals = || parser::needs_par_as_let_scrutinee(init.precedence());
|
||||
self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
|
||||
}
|
||||
|
||||
|
|
@ -2160,47 +2156,50 @@ impl<'a> State<'a> {
|
|||
if i != 0 {
|
||||
self.word_space(",");
|
||||
}
|
||||
self.print_where_predicate(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
match *predicate {
|
||||
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params,
|
||||
bounded_ty,
|
||||
bounds,
|
||||
..
|
||||
}) => {
|
||||
self.print_formal_generic_params(bound_generic_params);
|
||||
self.print_type(bounded_ty);
|
||||
self.print_bounds(":", bounds);
|
||||
}
|
||||
hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime,
|
||||
bounds,
|
||||
..
|
||||
}) => {
|
||||
self.print_lifetime(lifetime);
|
||||
self.word(":");
|
||||
fn print_where_predicate(&mut self, predicate: &hir::WherePredicate<'_>) {
|
||||
match *predicate.kind {
|
||||
hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bound_generic_params,
|
||||
bounded_ty,
|
||||
bounds,
|
||||
..
|
||||
}) => {
|
||||
self.print_formal_generic_params(bound_generic_params);
|
||||
self.print_type(bounded_ty);
|
||||
self.print_bounds(":", bounds);
|
||||
}
|
||||
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime,
|
||||
bounds,
|
||||
..
|
||||
}) => {
|
||||
self.print_lifetime(lifetime);
|
||||
self.word(":");
|
||||
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
match bound {
|
||||
GenericBound::Outlives(lt) => {
|
||||
self.print_lifetime(lt);
|
||||
}
|
||||
_ => panic!("unexpected bound on lifetime param: {bound:?}"),
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
match bound {
|
||||
GenericBound::Outlives(lt) => {
|
||||
self.print_lifetime(lt);
|
||||
}
|
||||
_ => panic!("unexpected bound on lifetime param: {bound:?}"),
|
||||
}
|
||||
|
||||
if i != 0 {
|
||||
self.word(":");
|
||||
}
|
||||
if i != 0 {
|
||||
self.word(":");
|
||||
}
|
||||
}
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty, rhs_ty, ..
|
||||
}) => {
|
||||
self.print_type(lhs_ty);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_type(rhs_ty);
|
||||
}
|
||||
}
|
||||
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty, rhs_ty, ..
|
||||
}) => {
|
||||
self.print_type(lhs_ty);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_type(rhs_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -606,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Ok(rest_snippet) = rest_snippet {
|
||||
let sugg = if callee_expr.precedence().order() >= PREC_UNAMBIGUOUS {
|
||||
let sugg = if callee_expr.precedence() >= PREC_UNAMBIGUOUS {
|
||||
vec![
|
||||
(up_to_rcvr_span, "".to_string()),
|
||||
(rest_span, format!(".{}({rest_snippet}", segment.ident)),
|
||||
|
|
|
|||
|
|
@ -1107,7 +1107,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
}
|
||||
|
||||
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
|
||||
let expr_prec = self.expr.precedence().order();
|
||||
let expr_prec = self.expr.precedence();
|
||||
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
|
||||
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// While we don't allow *arbitrary* coercions here, we *do* allow
|
||||
// coercions from ! to `expected`.
|
||||
if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) {
|
||||
if self.try_structurally_resolve_type(expr.span, ty).is_never()
|
||||
&& self.expr_guaranteed_to_constitute_read_for_never(expr)
|
||||
{
|
||||
if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
|
||||
let reported = self.dcx().span_delayed_bug(
|
||||
expr.span,
|
||||
|
|
@ -274,7 +276,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// unless it's a place expression that isn't being read from, in which case
|
||||
// diverging would be unsound since we may never actually read the `!`.
|
||||
// e.g. `let _ = *never_ptr;` with `never_ptr: *const !`.
|
||||
if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) {
|
||||
if self.try_structurally_resolve_type(expr.span, ty).is_never()
|
||||
&& self.expr_guaranteed_to_constitute_read_for_never(expr)
|
||||
{
|
||||
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| hir::Node::GenericParam(_)
|
||||
| hir::Node::Crate(_)
|
||||
| hir::Node::Infer(_)
|
||||
| hir::Node::WhereBoundPredicate(_)
|
||||
| hir::Node::WherePredicate(_)
|
||||
| hir::Node::ArrayLenInfer(_)
|
||||
| hir::Node::PreciseCapturingNonLifetimeArg(_)
|
||||
| hir::Node::OpaqueTy(_) => {
|
||||
|
|
|
|||
|
|
@ -269,13 +269,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
Adjust::Deref(None) => {
|
||||
// FIXME(effects): We *could* enforce `&T: ~const Deref` here.
|
||||
// FIXME(const_trait_impl): We *could* enforce `&T: ~const Deref` here.
|
||||
}
|
||||
Adjust::Pointer(_pointer_coercion) => {
|
||||
// FIXME(effects): We should probably enforce these.
|
||||
// FIXME(const_trait_impl): We should probably enforce these.
|
||||
}
|
||||
Adjust::ReborrowPin(_mutability) => {
|
||||
// FIXME(effects): We could enforce these; they correspond to
|
||||
// FIXME(const_trait_impl): We could enforce these; they correspond to
|
||||
// `&mut T: DerefMut` tho, so it's kinda moot.
|
||||
}
|
||||
Adjust::Borrow(_) => {
|
||||
|
|
|
|||
|
|
@ -729,7 +729,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let can_coerce = self.may_coerce(arg_ty, coerced_ty);
|
||||
if !can_coerce {
|
||||
return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts(
|
||||
ty::error::ExpectedFound::new(true, coerced_ty, arg_ty),
|
||||
ty::error::ExpectedFound::new(coerced_ty, arg_ty),
|
||||
)));
|
||||
}
|
||||
|
||||
|
|
@ -758,7 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
expected_ty
|
||||
};
|
||||
TypeTrace::types(&self.misc(span), true, mismatched_ty, provided_ty)
|
||||
TypeTrace::types(&self.misc(span), mismatched_ty, provided_ty)
|
||||
};
|
||||
|
||||
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
|
||||
|
|
@ -2347,9 +2347,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let check_for_matched_generics = || {
|
||||
if matched_inputs.iter().any(|x| x.is_some())
|
||||
&& params_with_generics.iter().any(|x| x.0.is_some())
|
||||
&& params_with_generics.iter().any(|x| x.1.is_some())
|
||||
{
|
||||
for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
|
||||
for &(idx, generic, _) in ¶ms_with_generics {
|
||||
// Param has to have a generic and be matched to be relevant
|
||||
if matched_inputs[idx.into()].is_none() {
|
||||
continue;
|
||||
|
|
@ -2362,7 +2362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for unmatching_idx in idx + 1..params_with_generics.len() {
|
||||
if matched_inputs[unmatching_idx.into()].is_none()
|
||||
&& let Some(unmatched_idx_param_generic) =
|
||||
params_with_generics[unmatching_idx].0
|
||||
params_with_generics[unmatching_idx].1
|
||||
&& unmatched_idx_param_generic.name.ident()
|
||||
== generic.name.ident()
|
||||
{
|
||||
|
|
@ -2377,8 +2377,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let check_for_matched_generics = check_for_matched_generics();
|
||||
|
||||
for (idx, (generic_param, param)) in
|
||||
params_with_generics.iter().enumerate().filter(|(idx, _)| {
|
||||
for &(idx, generic_param, param) in
|
||||
params_with_generics.iter().filter(|&(idx, _, _)| {
|
||||
check_for_matched_generics
|
||||
|| expected_idx.is_none_or(|expected_idx| expected_idx == *idx)
|
||||
})
|
||||
|
|
@ -2390,8 +2390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(other_idx, (other_generic_param, _))| {
|
||||
.filter(|(other_idx, other_generic_param, _)| {
|
||||
if *other_idx == idx {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2410,18 +2409,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
other_generic_param.name.ident() == generic_param.name.ident()
|
||||
})
|
||||
.map(|(other_idx, (_, other_param))| (other_idx, *other_param))
|
||||
.map(|&(other_idx, _, other_param)| (other_idx, other_param))
|
||||
.collect();
|
||||
|
||||
if !other_params_matched.is_empty() {
|
||||
let other_param_matched_names: Vec<String> = other_params_matched
|
||||
.iter()
|
||||
.map(|(_, other_param)| {
|
||||
.map(|(idx, other_param)| {
|
||||
if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind
|
||||
{
|
||||
format!("`{ident}`")
|
||||
} else {
|
||||
"{unknown}".to_string()
|
||||
format!("parameter #{}", idx + 1)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -2478,18 +2477,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let param_idents_matching: Vec<String> = params_with_generics
|
||||
.iter()
|
||||
.filter(|(generic, _)| {
|
||||
.filter(|(_, generic, _)| {
|
||||
if let Some(generic) = generic {
|
||||
generic.name.ident() == generic_param.name.ident()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|(_, param)| {
|
||||
.map(|(idx, _, param)| {
|
||||
if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
|
||||
format!("`{ident}`")
|
||||
} else {
|
||||
"{unknown}".to_string()
|
||||
format!("parameter #{}", idx + 1)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -2498,8 +2497,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
spans.push_span_label(
|
||||
generic_param.span,
|
||||
format!(
|
||||
"{} all reference this parameter {}",
|
||||
"{} {} reference this parameter `{}`",
|
||||
display_list_with_comma_and(¶m_idents_matching),
|
||||
if param_idents_matching.len() == 2 { "both" } else { "all" },
|
||||
generic_param.name.ident().name,
|
||||
),
|
||||
);
|
||||
|
|
@ -2580,7 +2580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) {
|
||||
debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
|
||||
for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
|
||||
for &(idx, generic_param, _) in ¶ms_with_generics {
|
||||
if matched_inputs[idx.into()].is_none() {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2594,20 +2594,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let mut idxs_matched: Vec<usize> = vec![];
|
||||
for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
|
||||
|(other_idx, (other_generic_param, _))| {
|
||||
if *other_idx == idx {
|
||||
for &(other_idx, _, _) in
|
||||
params_with_generics.iter().filter(|&&(other_idx, other_generic_param, _)| {
|
||||
if other_idx == idx {
|
||||
return false;
|
||||
}
|
||||
let Some(other_generic_param) = other_generic_param else {
|
||||
return false;
|
||||
};
|
||||
if matched_inputs[(*other_idx).into()].is_some() {
|
||||
if matched_inputs[other_idx.into()].is_some() {
|
||||
return false;
|
||||
}
|
||||
other_generic_param.name.ident() == generic_param.name.ident()
|
||||
},
|
||||
) {
|
||||
})
|
||||
{
|
||||
idxs_matched.push(other_idx);
|
||||
}
|
||||
|
||||
|
|
@ -2642,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
def_id: DefId,
|
||||
is_method: bool,
|
||||
) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> {
|
||||
) -> Option<Vec<(usize, Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> {
|
||||
let fn_node = self.tcx.hir().get_if_local(def_id)?;
|
||||
let fn_decl = fn_node.fn_decl()?;
|
||||
|
||||
|
|
@ -2685,7 +2685,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
debug_assert_eq!(params.len(), generic_params.len());
|
||||
Some(generic_params.into_iter().zip(params).collect())
|
||||
Some(
|
||||
generic_params
|
||||
.into_iter()
|
||||
.zip(params)
|
||||
.enumerate()
|
||||
.map(|(a, (b, c))| (a, b, c))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use core::cmp::min;
|
|||
use core::iter;
|
||||
|
||||
use hir::def_id::LocalDefId;
|
||||
use rustc_ast::util::parser::{ExprPrecedence, PREC_UNAMBIGUOUS};
|
||||
use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -10,7 +10,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
|
||||
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind,
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
|
|
@ -398,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// so we remove the user's `clone` call.
|
||||
{
|
||||
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
|
||||
} else if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
|
||||
} else if expr.precedence() < PREC_UNAMBIGUOUS {
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
||||
|
|
@ -1004,8 +1004,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// get all where BoundPredicates here, because they are used in two cases below
|
||||
let where_predicates = predicates
|
||||
.iter()
|
||||
.filter_map(|p| match p {
|
||||
WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||
.filter_map(|p| match p.kind {
|
||||
WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
|
||||
bounds,
|
||||
bounded_ty,
|
||||
..
|
||||
|
|
@ -1376,7 +1376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
|
||||
|
||||
let mut sugg = if expr.precedence().order() >= PREC_UNAMBIGUOUS {
|
||||
let mut sugg = if expr.precedence() >= PREC_UNAMBIGUOUS {
|
||||
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
||||
} else {
|
||||
vec![
|
||||
|
|
@ -3000,7 +3000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
|
||||
);
|
||||
|
||||
let close_paren = if expr.precedence().order() < PREC_UNAMBIGUOUS {
|
||||
let close_paren = if expr.precedence() < PREC_UNAMBIGUOUS {
|
||||
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
|
||||
")"
|
||||
} else {
|
||||
|
|
@ -3025,7 +3025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let len = src.trim_end_matches(&checked_ty.to_string()).len();
|
||||
expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
|
||||
},
|
||||
if expr.precedence().order() < PREC_UNAMBIGUOUS {
|
||||
if expr.precedence() < PREC_UNAMBIGUOUS {
|
||||
// Readd `)`
|
||||
format!("{expected_ty})")
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ fn report_unexpected_variant_res(
|
|||
.with_code(err_code);
|
||||
match res {
|
||||
Res::Def(DefKind::Fn | DefKind::AssocFn, _) if err_code == E0164 => {
|
||||
let patterns_url = "https://doc.rust-lang.org/book/ch18-00-patterns.html";
|
||||
let patterns_url = "https://doc.rust-lang.org/book/ch19-00-patterns.html";
|
||||
err.with_span_label(span, "`fn` calls are not allowed in patterns")
|
||||
.with_help(format!("for more information, visit {patterns_url}"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1802,7 +1802,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut is_mutbl = bm.1;
|
||||
|
||||
for pointer_ty in place.deref_tys() {
|
||||
match pointer_ty.kind() {
|
||||
match self.structurally_resolve_type(self.tcx.hir().span(var_hir_id), pointer_ty).kind()
|
||||
{
|
||||
// We don't capture derefs of raw ptrs
|
||||
ty::RawPtr(_, _) => unreachable!(),
|
||||
|
||||
|
|
@ -1816,7 +1817,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Dereferencing a box doesn't change mutability
|
||||
ty::Adt(def, ..) if def.is_box() => {}
|
||||
|
||||
unexpected_ty => bug!("deref of unexpected pointer type {:?}", unexpected_ty),
|
||||
unexpected_ty => span_bug!(
|
||||
self.tcx.hir().span(var_hir_id),
|
||||
"deref of unexpected pointer type {:?}",
|
||||
unexpected_ty
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,15 @@ mod persist;
|
|||
|
||||
pub use persist::{
|
||||
LoadResult, copy_cgu_workproduct_to_incr_comp_cache_dir, finalize_session_directory,
|
||||
in_incr_comp_dir, in_incr_comp_dir_sess, load_query_result_cache, save_dep_graph,
|
||||
save_work_product_index, setup_dep_graph,
|
||||
in_incr_comp_dir, in_incr_comp_dir_sess, load_query_result_cache, save_work_product_index,
|
||||
setup_dep_graph,
|
||||
};
|
||||
use rustc_middle::util::Providers;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
providers.hooks.save_dep_graph =
|
||||
|tcx| tcx.sess.time("serialize_dep_graph", || persist::save_dep_graph(tcx.tcx));
|
||||
}
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@ mod work_product;
|
|||
|
||||
pub use fs::{finalize_session_directory, in_incr_comp_dir, in_incr_comp_dir_sess};
|
||||
pub use load::{LoadResult, load_query_result_cache, setup_dep_graph};
|
||||
pub use save::{save_dep_graph, save_work_product_index};
|
||||
pub(crate) use save::save_dep_graph;
|
||||
pub use save::save_work_product_index;
|
||||
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::errors;
|
|||
///
|
||||
/// This function should only run after all queries have completed.
|
||||
/// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
|
||||
pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
||||
pub(crate) fn save_dep_graph(tcx: TyCtxt<'_>) {
|
||||
debug!("save_dep_graph()");
|
||||
tcx.dep_graph.with_ignore(|| {
|
||||
let sess = tcx.sess;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ impl Parse for Newtype {
|
|||
#gate_rustc_only
|
||||
impl ::std::iter::Step for #name {
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
|
||||
<usize as ::std::iter::Step>::steps_between(
|
||||
&Self::index(*start),
|
||||
&Self::index(*end),
|
||||
|
|
|
|||
|
|
@ -308,17 +308,14 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
|
|||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Regions(ExpectedFound::new(true, a, b)),
|
||||
}
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +323,7 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
|
|||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -337,13 +334,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
|||
cause: cause.clone(),
|
||||
values: match (a.unpack(), b.unpack()) {
|
||||
(GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
|
||||
ValuePairs::Regions(ExpectedFound::new(true, a, b))
|
||||
ValuePairs::Regions(ExpectedFound::new(a, b))
|
||||
}
|
||||
(GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
|
||||
ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
|
||||
ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
|
||||
}
|
||||
(GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
|
||||
ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into()))
|
||||
ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
|
||||
}
|
||||
_ => bug!("relating different kinds: {a:?} {b:?}"),
|
||||
},
|
||||
|
|
@ -353,19 +350,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
|
|||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(true, a, b)),
|
||||
}
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::TraitRefs(ExpectedFound::new(true, a, b)),
|
||||
}
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,17 +364,14 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
|
|||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Aliases(ExpectedFound::new(true, a.into(), b.into())),
|
||||
values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Aliases(ExpectedFound::new(true, a, b)),
|
||||
}
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +380,6 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
|
|||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::PolySigs(ExpectedFound::new(
|
||||
true,
|
||||
ty::Binder::dummy(a),
|
||||
ty::Binder::dummy(b),
|
||||
)),
|
||||
|
|
@ -402,10 +389,7 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
|
|||
|
||||
impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
|
||||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::PolySigs(ExpectedFound::new(true, a, b)),
|
||||
}
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -413,7 +397,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
|
|||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(true, a, b)),
|
||||
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -422,7 +406,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
|
|||
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::ExistentialProjection(ExpectedFound::new(true, a, b)),
|
||||
values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
query_state,
|
||||
)
|
||||
.unchecked_map(|(param_env, value)| param_env.and(value));
|
||||
CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) }
|
||||
CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }
|
||||
}
|
||||
|
||||
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
||||
|
|
|
|||
|
|
@ -20,11 +20,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.next_trait_solver
|
||||
}
|
||||
|
||||
fn typing_mode(
|
||||
&self,
|
||||
param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
|
||||
) -> ty::TypingMode<'tcx> {
|
||||
self.typing_mode(param_env_for_debug_assertion)
|
||||
fn typing_mode(&self) -> ty::TypingMode<'tcx> {
|
||||
self.typing_mode()
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_type_ir::solve::Reveal;
|
||||
use snapshot::undo_log::InferCtxtUndoLogs;
|
||||
use tracing::{debug, instrument};
|
||||
use type_variable::TypeVariableOrigin;
|
||||
|
|
@ -265,11 +264,12 @@ pub struct InferCtxt<'tcx> {
|
|||
lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>,
|
||||
|
||||
/// Caches the results of trait selection. This cache is used
|
||||
/// for things that have to do with the parameters in scope.
|
||||
pub selection_cache: select::SelectionCache<'tcx>,
|
||||
/// for things that depends on inference variables or placeholders.
|
||||
pub selection_cache: select::SelectionCache<'tcx, ty::ParamEnv<'tcx>>,
|
||||
|
||||
/// Caches the results of trait evaluation.
|
||||
pub evaluation_cache: select::EvaluationCache<'tcx>,
|
||||
/// Caches the results of trait evaluation. This cache is used
|
||||
/// for things that depends on inference variables or placeholders.
|
||||
pub evaluation_cache: select::EvaluationCache<'tcx, ty::ParamEnv<'tcx>>,
|
||||
|
||||
/// The set of predicates on which errors have been reported, to
|
||||
/// avoid reporting the same error twice.
|
||||
|
|
@ -624,22 +624,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn typing_mode(
|
||||
&self,
|
||||
param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
|
||||
) -> TypingMode<'tcx> {
|
||||
if cfg!(debug_assertions) {
|
||||
match (param_env_for_debug_assertion.reveal(), self.typing_mode) {
|
||||
(Reveal::All, TypingMode::PostAnalysis)
|
||||
| (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {}
|
||||
(r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"),
|
||||
}
|
||||
}
|
||||
self.typing_mode
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> {
|
||||
pub fn typing_mode(&self) -> TypingMode<'tcx> {
|
||||
self.typing_mode
|
||||
}
|
||||
|
||||
|
|
@ -1005,7 +990,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
|
||||
match self.typing_mode_unchecked() {
|
||||
match self.typing_mode() {
|
||||
TypingMode::Analysis { defining_opaque_types } => {
|
||||
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
|
||||
}
|
||||
|
|
@ -1290,7 +1275,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// which contains the necessary information to use the trait system without
|
||||
/// using canonicalization or carrying this inference context around.
|
||||
pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
|
||||
let typing_mode = match self.typing_mode(param_env) {
|
||||
let typing_mode = match self.typing_mode() {
|
||||
ty::TypingMode::Coherence => ty::TypingMode::Coherence,
|
||||
// FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible
|
||||
// to handle them without proper canonicalization. This means we may cause cycle
|
||||
|
|
@ -1478,39 +1463,29 @@ impl<'tcx> TypeTrace<'tcx> {
|
|||
self.cause.span
|
||||
}
|
||||
|
||||
pub fn types(
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
) -> TypeTrace<'tcx> {
|
||||
pub fn types(cause: &ObligationCause<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_refs(
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: ty::TraitRef<'tcx>,
|
||||
b: ty::TraitRef<'tcx>,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
|
||||
}
|
||||
TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
|
||||
}
|
||||
|
||||
pub fn consts(
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: cause.clone(),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
|
||||
values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
||||
let def_id = def_id.expect_local();
|
||||
if let ty::TypingMode::Coherence = self.typing_mode(param_env) {
|
||||
if let ty::TypingMode::Coherence = self.typing_mode() {
|
||||
// See comment on `insert_hidden_type` for why this is sufficient in coherence
|
||||
return Some(self.register_hidden_type(
|
||||
OpaqueTypeKey { def_id, args },
|
||||
|
|
@ -177,7 +177,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
res
|
||||
} else {
|
||||
let (a, b) = self.resolve_vars_if_possible((a, b));
|
||||
Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
|
||||
Err(TypeError::Sorts(ExpectedFound::new(a, b)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -522,7 +522,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// value being folded. In simple cases like `-> impl Foo`,
|
||||
// these are the same span, but not in cases like `-> (impl
|
||||
// Foo, impl Bar)`.
|
||||
match self.typing_mode(param_env) {
|
||||
match self.typing_mode() {
|
||||
ty::TypingMode::Coherence => {
|
||||
// During intercrate we do not define opaque types but instead always
|
||||
// force ambiguity unless the hidden type is known to not implement
|
||||
|
|
|
|||
|
|
@ -520,10 +520,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
|
|||
//
|
||||
// cc trait-system-refactor-initiative#108
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !matches!(
|
||||
self.infcx.typing_mode_unchecked(),
|
||||
TypingMode::Coherence
|
||||
)
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& self.in_alias
|
||||
{
|
||||
inner.type_variables().equate(vid, new_var_id);
|
||||
|
|
@ -654,10 +651,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
|
|||
// See the comment for type inference variables
|
||||
// for more details.
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !matches!(
|
||||
self.infcx.typing_mode_unchecked(),
|
||||
TypingMode::Coherence
|
||||
)
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& self.in_alias
|
||||
{
|
||||
variable_table.union(vid, new_var_id);
|
||||
|
|
|
|||
|
|
@ -689,10 +689,12 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
|
|||
rustc_const_eval::provide(providers);
|
||||
rustc_middle::hir::provide(providers);
|
||||
rustc_borrowck::provide(providers);
|
||||
rustc_incremental::provide(providers);
|
||||
rustc_mir_build::provide(providers);
|
||||
rustc_mir_transform::provide(providers);
|
||||
rustc_monomorphize::provide(providers);
|
||||
rustc_privacy::provide(providers);
|
||||
rustc_query_impl::provide(providers);
|
||||
rustc_resolve::provide(providers);
|
||||
rustc_hir_analysis::provide(providers);
|
||||
rustc_hir_typeck::provide(providers);
|
||||
|
|
|
|||
|
|
@ -12,13 +12,12 @@ use rustc_hir::def_id::LOCAL_CRATE;
|
|||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::DepGraph;
|
||||
use rustc_middle::ty::{GlobalCtxt, TyCtxt};
|
||||
use rustc_serialize::opaque::FileEncodeResult;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, OutputFilenames, OutputType};
|
||||
|
||||
use crate::errors::FailedWritingFile;
|
||||
use crate::interface::{Compiler, Result};
|
||||
use crate::{errors, passes};
|
||||
use crate::passes;
|
||||
|
||||
/// Represent the result of a query.
|
||||
///
|
||||
|
|
@ -62,7 +61,7 @@ impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> {
|
|||
|
||||
impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> {
|
||||
pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
|
||||
(*self.0).get_mut().enter(f)
|
||||
(*self.0).borrow().enter(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,8 +89,10 @@ impl<'tcx> Queries<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn finish(&self) -> FileEncodeResult {
|
||||
if let Some(gcx) = self.gcx_cell.get() { gcx.finish() } else { Ok(0) }
|
||||
pub fn finish(&'tcx self) {
|
||||
if let Some(gcx) = self.gcx_cell.get() {
|
||||
gcx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
|
||||
|
|
@ -209,29 +210,10 @@ impl Compiler {
|
|||
let queries = Queries::new(self);
|
||||
let ret = f(&queries);
|
||||
|
||||
// NOTE: intentionally does not compute the global context if it hasn't been built yet,
|
||||
// since that likely means there was a parse error.
|
||||
if let Some(Ok(gcx)) = &mut *queries.gcx.result.borrow_mut() {
|
||||
let gcx = gcx.get_mut();
|
||||
// We assume that no queries are run past here. If there are new queries
|
||||
// after this point, they'll show up as "<unknown>" in self-profiling data.
|
||||
{
|
||||
let _prof_timer =
|
||||
queries.compiler.sess.prof.generic_activity("self_profile_alloc_query_strings");
|
||||
gcx.enter(rustc_query_impl::alloc_self_profile_query_strings);
|
||||
}
|
||||
|
||||
self.sess.time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph));
|
||||
|
||||
gcx.enter(rustc_query_impl::query_key_hash_verify_all);
|
||||
}
|
||||
|
||||
// The timer's lifetime spans the dropping of `queries`, which contains
|
||||
// the global context.
|
||||
_timer = self.sess.timer("free_global_ctxt");
|
||||
if let Err((path, error)) = queries.finish() {
|
||||
self.sess.dcx().emit_fatal(errors::FailedWritingFile { path: &path, error });
|
||||
}
|
||||
queries.finish();
|
||||
|
||||
ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -784,7 +784,6 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(flatten_format_args, false);
|
||||
tracked!(fmt_debug, FmtDebug::Shallow);
|
||||
tracked!(force_unstable_if_unmarked, true);
|
||||
tracked!(fuel, Some(("abc".to_string(), 99)));
|
||||
tracked!(function_return, FunctionReturn::ThunkExtern);
|
||||
tracked!(function_sections, Some(false));
|
||||
tracked!(human_readable_cgu_names, true);
|
||||
|
|
@ -830,7 +829,6 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(plt, Some(true));
|
||||
tracked!(polonius, Polonius::Legacy);
|
||||
tracked!(precise_enum_drop_elaboration, false);
|
||||
tracked!(print_fuel, Some("abc".to_string()));
|
||||
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
|
||||
tracked!(profiler_runtime, "abc".to_string());
|
||||
tracked!(regparm, Some(3));
|
||||
|
|
|
|||
|
|
@ -566,19 +566,19 @@ impl Cursor<'_> {
|
|||
|
||||
fn c_or_byte_string(
|
||||
&mut self,
|
||||
mk_kind: impl FnOnce(bool) -> LiteralKind,
|
||||
mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
|
||||
mk_kind: fn(bool) -> LiteralKind,
|
||||
mk_kind_raw: fn(Option<u8>) -> LiteralKind,
|
||||
single_quoted: Option<fn(bool) -> LiteralKind>,
|
||||
) -> TokenKind {
|
||||
match (self.first(), self.second(), single_quoted) {
|
||||
('\'', _, Some(mk_kind)) => {
|
||||
('\'', _, Some(single_quoted)) => {
|
||||
self.bump();
|
||||
let terminated = self.single_quoted_string();
|
||||
let suffix_start = self.pos_within_token();
|
||||
if terminated {
|
||||
self.eat_literal_suffix();
|
||||
}
|
||||
let kind = mk_kind(terminated);
|
||||
let kind = single_quoted(terminated);
|
||||
Literal { kind, suffix_start }
|
||||
}
|
||||
('"', _, _) => {
|
||||
|
|
|
|||
|
|
@ -77,63 +77,53 @@ fn test_too_many_hashes() {
|
|||
check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/70528
|
||||
#[test]
|
||||
fn test_valid_shebang() {
|
||||
// https://github.com/rust-lang/rust/issues/70528
|
||||
let input = "#!/usr/bin/rustrun\nlet x = 5;";
|
||||
assert_eq!(strip_shebang(input), Some(18));
|
||||
}
|
||||
let input = "#!/bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
|
||||
#[test]
|
||||
fn test_invalid_shebang_valid_rust_syntax() {
|
||||
// https://github.com/rust-lang/rust/issues/70528
|
||||
let input = "#! [bad_attribute]";
|
||||
let input = "#![attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
|
||||
let input = "#! [attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! /* blah */ /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
|
||||
let input = "#! /* blah */ [attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! // blah\n/bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(10)); // strip up to the newline
|
||||
|
||||
let input = "#! // blah\n[attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#! /* blah\nblah\nblah */ /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(10));
|
||||
|
||||
let input = "#! /* blah\nblah\nblah */ [attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
|
||||
let input = "#!\n/bin/sh";
|
||||
assert_eq!(strip_shebang(input), Some(2));
|
||||
|
||||
let input = "#!\n[attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_second_line() {
|
||||
// Because shebangs are interpreted by the kernel, they must be on the first line
|
||||
let input = "\n#!/bin/bash";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_space() {
|
||||
let input = "#! /bin/bash";
|
||||
assert_eq!(strip_shebang(input), Some(input.len()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_empty_shebang() {
|
||||
let input = "#! \n[attribute(foo)]";
|
||||
let input = "\n#![attribute]";
|
||||
assert_eq!(strip_shebang(input), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_shebang_comment() {
|
||||
let input = "#!//bin/ami/a/comment\n[";
|
||||
assert_eq!(strip_shebang(input), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_shebang_another_comment() {
|
||||
let input = "#!/*bin/ami/a/comment*/\n[attribute";
|
||||
assert_eq!(strip_shebang(input), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_valid_rust_after() {
|
||||
let input = "#!/*bin/ami/a/comment*/\npub fn main() {}";
|
||||
assert_eq!(strip_shebang(input), Some(23))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shebang_followed_by_attrib() {
|
||||
let input = "#!/bin/rust-scripts\n#![allow_unused(true)]";
|
||||
assert_eq!(strip_shebang(input), Some(19));
|
||||
}
|
||||
|
||||
fn check_lexing(src: &str, expect: Expect) {
|
||||
let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect();
|
||||
expect.assert_eq(&actual)
|
||||
|
|
|
|||
|
|
@ -1407,7 +1407,7 @@ declare_lint_pass!(TypeAliasBounds => [TYPE_ALIAS_BOUNDS]);
|
|||
impl TypeAliasBounds {
|
||||
pub(crate) fn affects_object_lifetime_defaults(pred: &hir::WherePredicate<'_>) -> bool {
|
||||
// Bounds of the form `T: 'a` with `T` type param affect object lifetime defaults.
|
||||
if let hir::WherePredicate::BoundPredicate(pred) = pred
|
||||
if let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind
|
||||
&& pred.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Outlives(_)))
|
||||
&& pred.bound_generic_params.is_empty() // indeed, even if absent from the RHS
|
||||
&& pred.bounded_ty.as_generic_param().is_some()
|
||||
|
|
@ -1451,11 +1451,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
|||
let mut inline_sugg = Vec::new();
|
||||
|
||||
for p in generics.predicates {
|
||||
let span = p.span();
|
||||
if p.in_where_clause() {
|
||||
let span = p.span;
|
||||
if p.kind.in_where_clause() {
|
||||
where_spans.push(span);
|
||||
} else {
|
||||
for b in p.bounds() {
|
||||
for b in p.kind.bounds() {
|
||||
inline_spans.push(b.span());
|
||||
}
|
||||
inline_sugg.push((span, String::new()));
|
||||
|
|
@ -2071,7 +2071,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
let num_where_predicates = hir_generics
|
||||
.predicates
|
||||
.iter()
|
||||
.filter(|predicate| predicate.in_where_clause())
|
||||
.filter(|predicate| predicate.kind.in_where_clause())
|
||||
.count();
|
||||
|
||||
let mut bound_count = 0;
|
||||
|
|
@ -2080,8 +2080,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
let mut dropped_where_predicate_count = 0;
|
||||
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
||||
let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
|
||||
match where_predicate {
|
||||
hir::WherePredicate::RegionPredicate(predicate) => {
|
||||
match where_predicate.kind {
|
||||
hir::WherePredicateKind::RegionPredicate(predicate) => {
|
||||
if let Some(ResolvedArg::EarlyBound(region_def_id)) =
|
||||
cx.tcx.named_bound_var(predicate.lifetime.hir_id)
|
||||
{
|
||||
|
|
@ -2090,21 +2090,21 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
cx.tcx,
|
||||
// don't warn if the inferred span actually came from the predicate we're looking at
|
||||
// this happens if the type is recursively defined
|
||||
inferred_outlives
|
||||
.iter()
|
||||
.filter(|(_, span)| !predicate.span.contains(*span)),
|
||||
inferred_outlives.iter().filter(|(_, span)| {
|
||||
!where_predicate.span.contains(*span)
|
||||
}),
|
||||
item.owner_id.def_id,
|
||||
region_def_id,
|
||||
),
|
||||
&predicate.bounds,
|
||||
predicate.span,
|
||||
where_predicate.span,
|
||||
predicate.in_where_clause,
|
||||
)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
hir::WherePredicate::BoundPredicate(predicate) => {
|
||||
hir::WherePredicateKind::BoundPredicate(predicate) => {
|
||||
// FIXME we can also infer bounds on associated types,
|
||||
// and should check for them here.
|
||||
match predicate.bounded_ty.kind {
|
||||
|
|
@ -2118,12 +2118,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
// don't warn if the inferred span actually came from the predicate we're looking at
|
||||
// this happens if the type is recursively defined
|
||||
inferred_outlives.iter().filter(|(_, span)| {
|
||||
!predicate.span.contains(*span)
|
||||
!where_predicate.span.contains(*span)
|
||||
}),
|
||||
index,
|
||||
),
|
||||
&predicate.bounds,
|
||||
predicate.span,
|
||||
where_predicate.span,
|
||||
predicate.origin == PredicateOrigin::WhereClause,
|
||||
)
|
||||
}
|
||||
|
|
@ -2161,7 +2161,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
} else if i + 1 < num_where_predicates {
|
||||
// If all the bounds on a predicate were inferable and there are
|
||||
// further predicates, we want to eat the trailing comma.
|
||||
let next_predicate_span = hir_generics.predicates[i + 1].span();
|
||||
let next_predicate_span = hir_generics.predicates[i + 1].span;
|
||||
if next_predicate_span.from_expansion() {
|
||||
where_lint_spans.push(predicate_span);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use rustc_feature::Features;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
||||
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||
|
|
@ -702,7 +701,6 @@ impl<'tcx> LateContext<'tcx> {
|
|||
/// The typing mode of the currently visited node. Use this when
|
||||
/// building a new `InferCtxt`.
|
||||
pub fn typing_mode(&self) -> TypingMode<'tcx> {
|
||||
debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing);
|
||||
// FIXME(#132279): In case we're in a body, we should use a typing
|
||||
// mode which reveals the opaque types defined by that body.
|
||||
TypingMode::non_body_analysis()
|
||||
|
|
|
|||
|
|
@ -130,11 +130,11 @@ impl DanglingPointerSearcher<'_, '_> {
|
|||
|
||||
fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
|
||||
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
|
||||
&& is_temporary_rvalue(receiver)
|
||||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||
&& owns_allocation(cx.tcx, ty)
|
||||
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
|
||||
{
|
||||
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
||||
cx.tcx.emit_node_span_lint(
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> {
|
|||
let affect_object_lifetime_defaults = self
|
||||
.preds
|
||||
.iter()
|
||||
.filter(|pred| pred.in_where_clause() == self.in_where_clause)
|
||||
.filter(|pred| pred.kind.in_where_clause() == self.in_where_clause)
|
||||
.any(|pred| TypeAliasBounds::affects_object_lifetime_defaults(pred));
|
||||
|
||||
// If there are any shorthand assoc tys, then the bounds can't be removed automatically.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue