Auto merge of #104990 - matthiaskrgr:rollup-oskk8v3, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #104955 (Switch rustdoc-gui test to function call) - #104976 (Prefer doc comments over `//`-comments in compiler) - #104984 (Remove Crate::primitives field) - #104989 (update Miri) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8c6bf2bee7
169 changed files with 1343 additions and 909 deletions
|
|
@ -111,8 +111,8 @@ impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
|
|||
}
|
||||
|
||||
impl Path {
|
||||
// Convert a span and an identifier to the corresponding
|
||||
// one-segment path.
|
||||
/// Convert a span and an identifier to the corresponding
|
||||
/// one-segment path.
|
||||
pub fn from_ident(ident: Ident) -> Path {
|
||||
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
|
||||
}
|
||||
|
|
@ -1283,7 +1283,7 @@ impl Expr {
|
|||
)
|
||||
}
|
||||
|
||||
// To a first-order approximation, is this a pattern
|
||||
/// To a first-order approximation, is this a pattern?
|
||||
pub fn is_approximately_pattern(&self) -> bool {
|
||||
match &self.peel_parens().kind {
|
||||
ExprKind::Box(_)
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ use thin_vec::thin_vec;
|
|||
pub struct MarkedAttrs(GrowableBitSet<AttrId>);
|
||||
|
||||
impl MarkedAttrs {
|
||||
// We have no idea how many attributes there will be, so just
|
||||
// initiate the vectors with 0 bits. We'll grow them as necessary.
|
||||
pub fn new() -> Self {
|
||||
// We have no idea how many attributes there will be, so just
|
||||
// initiate the vectors with 0 bits. We'll grow them as necessary.
|
||||
MarkedAttrs(GrowableBitSet::new_empty())
|
||||
}
|
||||
|
||||
|
|
@ -174,9 +174,11 @@ impl MetaItem {
|
|||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
}
|
||||
|
||||
// Example:
|
||||
// #[attribute(name = "value")]
|
||||
// ^^^^^^^^^^^^^^
|
||||
/// ```text
|
||||
/// Example:
|
||||
/// #[attribute(name = "value")]
|
||||
/// ^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
pub fn name_value_literal(&self) -> Option<&Lit> {
|
||||
match &self.kind {
|
||||
MetaItemKind::NameValue(v) => Some(v),
|
||||
|
|
|
|||
|
|
@ -725,10 +725,10 @@ pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>,
|
|||
visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis);
|
||||
}
|
||||
|
||||
/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
|
||||
/// In practice the ident part is not actually used by specific visitors right now,
|
||||
/// but there's a test below checking that it works.
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
|
||||
// In practice the ident part is not actually used by specific visitors right now,
|
||||
// but there's a test below checking that it works.
|
||||
pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
|
||||
let Token { kind, span } = t;
|
||||
match kind {
|
||||
|
|
|
|||
|
|
@ -302,9 +302,9 @@ impl TokenKind {
|
|||
Literal(Lit::new(kind, symbol, suffix))
|
||||
}
|
||||
|
||||
// An approximation to proc-macro-style single-character operators used by rustc parser.
|
||||
// If the operator token can be broken into two tokens, the first of which is single-character,
|
||||
// then this function performs that operation, otherwise it returns `None`.
|
||||
/// An approximation to proc-macro-style single-character operators used by rustc parser.
|
||||
/// If the operator token can be broken into two tokens, the first of which is single-character,
|
||||
/// then this function performs that operation, otherwise it returns `None`.
|
||||
pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
|
||||
Some(match *self {
|
||||
Le => (Lt, Eq),
|
||||
|
|
@ -538,10 +538,10 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
// A convenience function for matching on identifiers during parsing.
|
||||
// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
|
||||
// into the regular identifier or lifetime token it refers to,
|
||||
// otherwise returns the original token.
|
||||
/// A convenience function for matching on identifiers during parsing.
|
||||
/// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
|
||||
/// into the regular identifier or lifetime token it refers to,
|
||||
/// otherwise returns the original token.
|
||||
pub fn uninterpolate(&self) -> Cow<'_, Token> {
|
||||
match &self.kind {
|
||||
Interpolated(nt) => match **nt {
|
||||
|
|
@ -621,7 +621,7 @@ impl Token {
|
|||
false
|
||||
}
|
||||
|
||||
// Is the token an interpolated block (`$b:block`)?
|
||||
/// Is the token an interpolated block (`$b:block`)?
|
||||
pub fn is_whole_block(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt {
|
||||
return true;
|
||||
|
|
@ -665,8 +665,8 @@ impl Token {
|
|||
self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
|
||||
}
|
||||
|
||||
// Returns true for reserved identifiers used internally for elided lifetimes,
|
||||
// unnamed method parameters, crate root module, error recovery etc.
|
||||
/// Returns true for reserved identifiers used internally for elided lifetimes,
|
||||
/// unnamed method parameters, crate root module, error recovery etc.
|
||||
pub fn is_special_ident(&self) -> bool {
|
||||
self.is_non_raw_ident_where(Ident::is_special)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,12 +86,12 @@ impl TokenTree {
|
|||
}
|
||||
}
|
||||
|
||||
// Create a `TokenTree::Token` with alone spacing.
|
||||
/// Create a `TokenTree::Token` with alone spacing.
|
||||
pub fn token_alone(kind: TokenKind, span: Span) -> TokenTree {
|
||||
TokenTree::Token(Token::new(kind, span), Spacing::Alone)
|
||||
}
|
||||
|
||||
// Create a `TokenTree::Token` with joint spacing.
|
||||
/// Create a `TokenTree::Token` with joint spacing.
|
||||
pub fn token_joint(kind: TokenKind, span: Span) -> TokenTree {
|
||||
TokenTree::Token(Token::new(kind, span), Spacing::Joint)
|
||||
}
|
||||
|
|
@ -413,17 +413,17 @@ impl TokenStream {
|
|||
TokenStream(Lrc::new(self.0.iter().enumerate().map(|(i, tree)| f(i, tree)).collect()))
|
||||
}
|
||||
|
||||
// Create a token stream containing a single token with alone spacing.
|
||||
/// Create a token stream containing a single token with alone spacing.
|
||||
pub fn token_alone(kind: TokenKind, span: Span) -> TokenStream {
|
||||
TokenStream::new(vec![TokenTree::token_alone(kind, span)])
|
||||
}
|
||||
|
||||
// Create a token stream containing a single token with joint spacing.
|
||||
/// Create a token stream containing a single token with joint spacing.
|
||||
pub fn token_joint(kind: TokenKind, span: Span) -> TokenStream {
|
||||
TokenStream::new(vec![TokenTree::token_joint(kind, span)])
|
||||
}
|
||||
|
||||
// Create a token stream containing a single `Delimited`.
|
||||
/// Create a token stream containing a single `Delimited`.
|
||||
pub fn delimited(span: DelimSpan, delim: Delimiter, tts: TokenStream) -> TokenStream {
|
||||
TokenStream::new(vec![TokenTree::Delimited(span, delim, tts)])
|
||||
}
|
||||
|
|
@ -522,8 +522,8 @@ impl TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
// Push `tt` onto the end of the stream, possibly gluing it to the last
|
||||
// token. Uses `make_mut` to maximize efficiency.
|
||||
/// Push `tt` onto the end of the stream, possibly gluing it to the last
|
||||
/// token. Uses `make_mut` to maximize efficiency.
|
||||
pub fn push_tree(&mut self, tt: TokenTree) {
|
||||
let vec_mut = Lrc::make_mut(&mut self.0);
|
||||
|
||||
|
|
@ -534,9 +534,9 @@ impl TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
// Push `stream` onto the end of the stream, possibly gluing the first
|
||||
// token tree to the last token. (No other token trees will be glued.)
|
||||
// Uses `make_mut` to maximize efficiency.
|
||||
/// Push `stream` onto the end of the stream, possibly gluing the first
|
||||
/// token tree to the last token. (No other token trees will be glued.)
|
||||
/// Uses `make_mut` to maximize efficiency.
|
||||
pub fn push_stream(&mut self, stream: TokenStream) {
|
||||
let vec_mut = Lrc::make_mut(&mut self.0);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ impl Printer {
|
|||
self.nbsp()
|
||||
}
|
||||
|
||||
// Synthesizes a comment that was not textually present in the original
|
||||
// source file.
|
||||
/// Synthesizes a comment that was not textually present in the original
|
||||
/// source file.
|
||||
pub fn synth_comment(&mut self, text: impl Into<Cow<'static, str>>) {
|
||||
self.word("/*");
|
||||
self.space();
|
||||
|
|
|
|||
|
|
@ -58,10 +58,10 @@ impl<'a> State<'a> {
|
|||
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
|
||||
}
|
||||
|
||||
// Does `expr` need parentheses when printed in a condition position?
|
||||
//
|
||||
// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
/// Does `expr` need parentheses when printed in a condition position?
|
||||
///
|
||||
/// These cases need parens due to the parse error observed in #26461: `if return {}`
|
||||
/// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
|
||||
pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
|
||||
match expr.kind {
|
||||
ast::ExprKind::Break(..)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub(crate) struct IncorrectMetaItem {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
// Error code: E0541
|
||||
/// Error code: E0541
|
||||
pub(crate) struct UnknownMetaItem<'a> {
|
||||
pub span: Span,
|
||||
pub item: String,
|
||||
|
|
@ -200,7 +200,7 @@ pub(crate) struct InvalidReprHintNoValue {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
// Error code: E0565
|
||||
/// Error code: E0565
|
||||
pub(crate) struct UnsupportedLiteral {
|
||||
pub span: Span,
|
||||
pub reason: UnsupportedLiteralReason,
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ impl UseSpans<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// Add a span label to the arguments of the closure, if it exists.
|
||||
/// Add a span label to the arguments of the closure, if it exists.
|
||||
pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.span_label(args_span, message);
|
||||
|
|
@ -628,7 +628,7 @@ impl UseSpans<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// Add a span label to the use of the captured variable, if it exists.
|
||||
/// Add a span label to the use of the captured variable, if it exists.
|
||||
pub(super) fn var_span_label(
|
||||
self,
|
||||
err: &mut Diagnostic,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ mod type_check;
|
|||
mod universal_regions;
|
||||
mod used_muts;
|
||||
|
||||
// A public API provided for the Rust compiler consumers.
|
||||
/// A public API provided for the Rust compiler consumers.
|
||||
pub mod consumers;
|
||||
|
||||
use borrow_set::{BorrowData, BorrowSet};
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// For every potentially drop()-touched region `region` in `local`'s type
|
||||
// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
|
||||
/// For every potentially drop()-touched region `region` in `local`'s type
|
||||
/// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
|
||||
pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
local: Local,
|
||||
|
|
|
|||
|
|
@ -300,12 +300,12 @@ struct TypeParameter {
|
|||
ty: P<ast::Ty>,
|
||||
}
|
||||
|
||||
// The code snippets built up for derived code are sometimes used as blocks
|
||||
// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
|
||||
// arm). This structure avoids committing to either form until necessary,
|
||||
// avoiding the insertion of any unnecessary blocks.
|
||||
//
|
||||
// The statements come before the expression.
|
||||
/// The code snippets built up for derived code are sometimes used as blocks
|
||||
/// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
|
||||
/// arm). This structure avoids committing to either form until necessary,
|
||||
/// avoiding the insertion of any unnecessary blocks.
|
||||
///
|
||||
/// The statements come before the expression.
|
||||
pub struct BlockOrExpr(Vec<ast::Stmt>, Option<P<Expr>>);
|
||||
|
||||
impl BlockOrExpr {
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@ use rustc_span::edition::Edition;
|
|||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
// This expands to either
|
||||
// - `$crate::panic::panic_2015!(...)` or
|
||||
// - `$crate::panic::panic_2021!(...)`
|
||||
// depending on the edition.
|
||||
//
|
||||
// This is used for both std::panic!() and core::panic!().
|
||||
//
|
||||
// `$crate` will refer to either the `std` or `core` crate depending on which
|
||||
// one we're expanding from.
|
||||
/// This expands to either
|
||||
/// - `$crate::panic::panic_2015!(...)` or
|
||||
/// - `$crate::panic::panic_2021!(...)`
|
||||
/// depending on the edition.
|
||||
///
|
||||
/// This is used for both std::panic!() and core::panic!().
|
||||
///
|
||||
/// `$crate` will refer to either the `std` or `core` crate depending on which
|
||||
/// one we're expanding from.
|
||||
pub fn expand_panic<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -24,10 +24,10 @@ pub fn expand_panic<'cx>(
|
|||
expand(mac, cx, sp, tts)
|
||||
}
|
||||
|
||||
// This expands to either
|
||||
// - `$crate::panic::unreachable_2015!(...)` or
|
||||
// - `$crate::panic::unreachable_2021!(...)`
|
||||
// depending on the edition.
|
||||
/// This expands to either
|
||||
/// - `$crate::panic::unreachable_2015!(...)` or
|
||||
/// - `$crate::panic::unreachable_2021!(...)`
|
||||
/// depending on the edition.
|
||||
pub fn expand_unreachable<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ pub fn expand_include<'cx>(
|
|||
Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
|
||||
}
|
||||
|
||||
// include_str! : read the given file, insert it as a literal string expr
|
||||
/// `include_str!`: read the given file, insert it as a literal string expr
|
||||
pub fn expand_include_str(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ use rustc_span::Span;
|
|||
use std::iter;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
// #[test_case] is used by custom test authors to mark tests
|
||||
// When building for test, it needs to make the item public and gensym the name
|
||||
// Otherwise, we'll omit the item. This behavior means that any item annotated
|
||||
// with #[test_case] is never addressable.
|
||||
//
|
||||
// We mark item with an inert attribute "rustc_test_marker" which the test generation
|
||||
// logic will pick up on.
|
||||
/// #[test_case] is used by custom test authors to mark tests
|
||||
/// When building for test, it needs to make the item public and gensym the name
|
||||
/// Otherwise, we'll omit the item. This behavior means that any item annotated
|
||||
/// with #[test_case] is never addressable.
|
||||
///
|
||||
/// We mark item with an inert attribute "rustc_test_marker" which the test generation
|
||||
/// logic will pick up on.
|
||||
pub fn expand_test_case(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
attr_sp: Span,
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ struct TestCtxt<'a> {
|
|||
test_runner: Option<ast::Path>,
|
||||
}
|
||||
|
||||
// Traverse the crate, collecting all the test functions, eliding any
|
||||
// existing main functions, and synthesizing a main test harness
|
||||
/// Traverse the crate, collecting all the test functions, eliding any
|
||||
/// existing main functions, and synthesizing a main test harness
|
||||
pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
|
||||
let span_diagnostic = sess.diagnostic();
|
||||
let panic_strategy = sess.panic_strategy();
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ impl<'tcx> CValue<'tcx> {
|
|||
}
|
||||
|
||||
// FIXME remove
|
||||
// Forces the data value of a dyn* value to the stack and returns a pointer to it as well as the
|
||||
// vtable pointer.
|
||||
/// Forces the data value of a dyn* value to the stack and returns a pointer to it as well as the
|
||||
/// vtable pointer.
|
||||
pub(crate) fn dyn_star_force_data_on_stack(
|
||||
self,
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -88,9 +88,9 @@ pub struct CodegenCx<'gcc, 'tcx> {
|
|||
pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
|
||||
|
||||
// TODO(antoyo): improve the SSA API to not require those.
|
||||
// Mapping from function pointer type to indexes of on stack parameters.
|
||||
/// Mapping from function pointer type to indexes of on stack parameters.
|
||||
pub on_stack_params: RefCell<FxHashMap<FunctionPtrType<'gcc>, FxHashSet<usize>>>,
|
||||
// Mapping from function to indexes of on stack parameters.
|
||||
/// Mapping from function to indexes of on stack parameters.
|
||||
pub on_stack_function_params: RefCell<FxHashMap<Function<'gcc>, FxHashSet<usize>>>,
|
||||
|
||||
/// Cache of emitted const globals (value -> global)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const VAR_ALIGN_BYTES: usize = 8;
|
|||
|
||||
/// A context object for maintaining all state needed by the coverageinfo module.
|
||||
pub struct CrateCoverageContext<'ll, 'tcx> {
|
||||
// Coverage data for each instrumented function identified by DefId.
|
||||
/// Coverage data for each instrumented function identified by DefId.
|
||||
pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub enum LLVMRustResult {
|
|||
pub struct LLVMRustCOFFShortExport {
|
||||
pub name: *const c_char,
|
||||
pub ordinal_present: bool,
|
||||
// value of `ordinal` only important when `ordinal_present` is true
|
||||
/// value of `ordinal` only important when `ordinal_present` is true
|
||||
pub ordinal: u16,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,8 +194,8 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
|
|||
}
|
||||
}
|
||||
|
||||
// Given a map from target_features to whether they are enabled or disabled,
|
||||
// ensure only valid combinations are allowed.
|
||||
/// Given a map from target_features to whether they are enabled or disabled,
|
||||
/// ensure only valid combinations are allowed.
|
||||
pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
|
|
@ -213,8 +213,8 @@ pub fn check_tied_features(
|
|||
return None;
|
||||
}
|
||||
|
||||
// Used to generate cfg variables and apply features
|
||||
// Must express features in the way Rust understands them
|
||||
/// Used to generate cfg variables and apply features
|
||||
/// Must express features in the way Rust understands them
|
||||
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
let target_machine = create_informational_target_machine(sess);
|
||||
let mut features: Vec<Symbol> = supported_target_features(sess)
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ impl Type {
|
|||
unsafe { llvm::LLVMInt8TypeInContext(llcx) }
|
||||
}
|
||||
|
||||
// Creates an integer type with the given number of bits, e.g., i24
|
||||
/// Creates an integer type with the given number of bits, e.g., i24
|
||||
pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type {
|
||||
unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1179,7 +1179,7 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool
|
|||
&& (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
|
||||
}
|
||||
|
||||
// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
|
||||
/// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
|
||||
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||
fn infer_from(
|
||||
sess: &Session,
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ pub fn disable_localization(linker: &mut Command) {
|
|||
linker.env("VSLANG", "1033");
|
||||
}
|
||||
|
||||
// The third parameter is for env vars, used on windows to set up the
|
||||
// path for MSVC to find its DLLs, and gcc to find its bundled
|
||||
// toolchain
|
||||
/// The third parameter is for env vars, used on windows to set up the
|
||||
/// path for MSVC to find its DLLs, and gcc to find its bundled
|
||||
/// toolchain
|
||||
pub fn get_linker<'a>(
|
||||
sess: &'a Session,
|
||||
linker: &Path,
|
||||
|
|
|
|||
|
|
@ -191,38 +191,38 @@ pub enum MetadataPosition {
|
|||
Last,
|
||||
}
|
||||
|
||||
// For rlibs we "pack" rustc metadata into a dummy object file.
|
||||
//
|
||||
// Historically it was needed because rustc linked rlibs as whole-archive in some cases.
|
||||
// In that case linkers try to include all files located in an archive, so if metadata is stored
|
||||
// in an archive then it needs to be of a form that the linker is able to process.
|
||||
// Now it's not clear whether metadata still needs to be wrapped into an object file or not.
|
||||
//
|
||||
// Note, though, that we don't actually want this metadata to show up in any
|
||||
// final output of the compiler. Instead this is purely for rustc's own
|
||||
// metadata tracking purposes.
|
||||
//
|
||||
// With the above in mind, each "flavor" of object format gets special
|
||||
// handling here depending on the target:
|
||||
//
|
||||
// * MachO - macos-like targets will insert the metadata into a section that
|
||||
// is sort of fake dwarf debug info. Inspecting the source of the macos
|
||||
// linker this causes these sections to be skipped automatically because
|
||||
// it's not in an allowlist of otherwise well known dwarf section names to
|
||||
// go into the final artifact.
|
||||
//
|
||||
// * WebAssembly - we actually don't have any container format for this
|
||||
// target. WebAssembly doesn't support the `dylib` crate type anyway so
|
||||
// there's no need for us to support this at this time. Consequently the
|
||||
// metadata bytes are simply stored as-is into an rlib.
|
||||
//
|
||||
// * COFF - Windows-like targets create an object with a section that has
|
||||
// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
|
||||
// ever sees the section it doesn't process it and it's removed.
|
||||
//
|
||||
// * ELF - All other targets are similar to Windows in that there's a
|
||||
// `SHF_EXCLUDE` flag we can set on sections in an object file to get
|
||||
// automatically removed from the final output.
|
||||
/// For rlibs we "pack" rustc metadata into a dummy object file.
|
||||
///
|
||||
/// Historically it was needed because rustc linked rlibs as whole-archive in some cases.
|
||||
/// In that case linkers try to include all files located in an archive, so if metadata is stored
|
||||
/// in an archive then it needs to be of a form that the linker is able to process.
|
||||
/// Now it's not clear whether metadata still needs to be wrapped into an object file or not.
|
||||
///
|
||||
/// Note, though, that we don't actually want this metadata to show up in any
|
||||
/// final output of the compiler. Instead this is purely for rustc's own
|
||||
/// metadata tracking purposes.
|
||||
///
|
||||
/// With the above in mind, each "flavor" of object format gets special
|
||||
/// handling here depending on the target:
|
||||
///
|
||||
/// * MachO - macos-like targets will insert the metadata into a section that
|
||||
/// is sort of fake dwarf debug info. Inspecting the source of the macos
|
||||
/// linker this causes these sections to be skipped automatically because
|
||||
/// it's not in an allowlist of otherwise well known dwarf section names to
|
||||
/// go into the final artifact.
|
||||
///
|
||||
/// * WebAssembly - we actually don't have any container format for this
|
||||
/// target. WebAssembly doesn't support the `dylib` crate type anyway so
|
||||
/// there's no need for us to support this at this time. Consequently the
|
||||
/// metadata bytes are simply stored as-is into an rlib.
|
||||
///
|
||||
/// * COFF - Windows-like targets create an object with a section that has
|
||||
/// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
|
||||
/// ever sees the section it doesn't process it and it's removed.
|
||||
///
|
||||
/// * ELF - All other targets are similar to Windows in that there's a
|
||||
/// `SHF_EXCLUDE` flag we can set on sections in an object file to get
|
||||
/// automatically removed from the final output.
|
||||
pub fn create_wrapper_file(
|
||||
sess: &Session,
|
||||
section_name: Vec<u8>,
|
||||
|
|
|
|||
|
|
@ -340,20 +340,20 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
|
||||
pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
|
||||
|
||||
// Number of cgus excluding the allocator/metadata modules
|
||||
/// Number of cgus excluding the allocator/metadata modules
|
||||
pub total_cgus: usize,
|
||||
// Handler to use for diagnostics produced during codegen.
|
||||
/// Handler to use for diagnostics produced during codegen.
|
||||
pub diag_emitter: SharedEmitter,
|
||||
// LLVM optimizations for which we want to print remarks.
|
||||
/// LLVM optimizations for which we want to print remarks.
|
||||
pub remark: Passes,
|
||||
// Worker thread number
|
||||
/// Worker thread number
|
||||
pub worker: usize,
|
||||
// The incremental compilation session directory, or None if we are not
|
||||
// compiling incrementally
|
||||
/// The incremental compilation session directory, or None if we are not
|
||||
/// compiling incrementally
|
||||
pub incr_comp_session_dir: Option<PathBuf>,
|
||||
// Used to update CGU re-use information during the thinlto phase.
|
||||
/// Used to update CGU re-use information during the thinlto phase.
|
||||
pub cgu_reuse_tracker: CguReuseTracker,
|
||||
// Channel back to the main control thread to send messages to
|
||||
/// Channel back to the main control thread to send messages to
|
||||
pub coordinator_send: Sender<Box<dyn Any + Send>>,
|
||||
}
|
||||
|
||||
|
|
@ -756,7 +756,7 @@ fn execute_work_item<B: ExtraBackendMethods>(
|
|||
}
|
||||
}
|
||||
|
||||
// Actual LTO type we end up choosing based on multiple factors.
|
||||
/// Actual LTO type we end up choosing based on multiple factors.
|
||||
pub enum ComputedLtoType {
|
||||
No,
|
||||
Thin,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Type Names for Debug Info.
|
||||
//! Type Names for Debug Info.
|
||||
|
||||
// Notes on targeting MSVC:
|
||||
// In general, MSVC's debugger attempts to parse all arguments as C++ expressions,
|
||||
|
|
@ -26,10 +26,10 @@ use std::fmt::Write;
|
|||
|
||||
use crate::debuginfo::wants_c_like_enum_debuginfo;
|
||||
|
||||
// Compute the name of the type as it should be stored in debuginfo. Does not do
|
||||
// any caching, i.e., calling the function twice with the same type will also do
|
||||
// the work twice. The `qualified` parameter only affects the first level of the
|
||||
// type name, further levels (i.e., type parameters) are always fully qualified.
|
||||
/// Compute the name of the type as it should be stored in debuginfo. Does not do
|
||||
/// any caching, i.e., calling the function twice with the same type will also do
|
||||
/// the work twice. The `qualified` parameter only affects the first level of the
|
||||
/// type name, further levels (i.e., type parameters) are always fully qualified.
|
||||
pub fn compute_debuginfo_type_name<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ pub enum OperandValue<V> {
|
|||
/// instead.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct OperandRef<'tcx, V> {
|
||||
// The value.
|
||||
/// The value.
|
||||
pub val: OperandValue<V>,
|
||||
|
||||
// The layout of value, based on its Rust type.
|
||||
/// The layout of value, based on its Rust type.
|
||||
pub layout: TyAndLayout<'tcx>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,8 +417,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
|
||||
// (CTFE and ConstProp) use the same instance. Here, we share that code.
|
||||
/// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
|
||||
/// (CTFE and ConstProp) use the same instance. Here, we share that code.
|
||||
pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||
type Provenance = AllocId;
|
||||
type ProvenanceExtra = ();
|
||||
|
|
|
|||
|
|
@ -206,8 +206,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Iterates over all fields of an array. Much more efficient than doing the
|
||||
// same by repeatedly calling `operand_index`.
|
||||
/// Iterates over all fields of an array. Much more efficient than doing the
|
||||
/// same by repeatedly calling `operand_index`.
|
||||
pub fn operand_array_fields<'a>(
|
||||
&self,
|
||||
base: &'a OpTy<'tcx, Prov>,
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueMut<'mir, 'tcx, M>
|
|||
|
||||
macro_rules! make_value_visitor {
|
||||
($visitor_trait:ident, $value_trait:ident, $($mutability:ident)?) => {
|
||||
// How to traverse a value and what to do when we are at the leaves.
|
||||
/// How to traverse a value and what to do when we are at the leaves.
|
||||
pub trait $visitor_trait<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
|
||||
type V: $value_trait<'mir, 'tcx, M>;
|
||||
|
||||
|
|
|
|||
|
|
@ -75,14 +75,14 @@ pub fn rustc_allow_const_fn_unstable(
|
|||
attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
|
||||
}
|
||||
|
||||
// Returns `true` if the given `const fn` is "const-stable".
|
||||
//
|
||||
// Panics if the given `DefId` does not refer to a `const fn`.
|
||||
//
|
||||
// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
|
||||
// functions can be called in a const-context by users of the stable compiler. "const-stable"
|
||||
// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
||||
// cannot use unstable features and can only call other "const-stable" functions.
|
||||
/// Returns `true` if the given `const fn` is "const-stable".
|
||||
///
|
||||
/// Panics if the given `DefId` does not refer to a `const fn`.
|
||||
///
|
||||
/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
|
||||
/// functions can be called in a const-context by users of the stable compiler. "const-stable"
|
||||
/// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
||||
/// cannot use unstable features and can only call other "const-stable" functions.
|
||||
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
// A default body in a `#[const_trait]` is not const-stable because const
|
||||
// trait fns currently cannot be const-stable. We shouldn't
|
||||
|
|
|
|||
|
|
@ -686,7 +686,7 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
|
|||
}
|
||||
}
|
||||
|
||||
// Types that cannot appear in the signature or locals of a `const fn`.
|
||||
/// Types that cannot appear in the signature or locals of a `const fn`.
|
||||
pub mod ty {
|
||||
use super::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ use std::iter::TrustedLen;
|
|||
/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
|
||||
///
|
||||
/// Produces something like
|
||||
///
|
||||
/// ```ignore (ilustrative)
|
||||
/// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum
|
||||
/// (lhs as Variant).field1 = arg1;
|
||||
/// discriminant(lhs) = variant_index; // If lhs is an enum or generator.
|
||||
/// ```
|
||||
pub fn expand_aggregate<'tcx>(
|
||||
orig_lhs: Place<'tcx>,
|
||||
operands: impl Iterator<Item = (Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
|
||||
|
|
|
|||
|
|
@ -1336,8 +1336,8 @@ mod signal_handler {
|
|||
}
|
||||
}
|
||||
|
||||
// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
|
||||
// process, print a stack trace and then exit.
|
||||
/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
|
||||
/// process, print a stack trace and then exit.
|
||||
pub(super) fn install() {
|
||||
unsafe {
|
||||
const ALT_STACK_SIZE: usize = libc::MINSIGSTKSZ + 64 * 1024;
|
||||
|
|
|
|||
|
|
@ -242,8 +242,8 @@ pub enum ExpandResult<T, U> {
|
|||
Retry(U),
|
||||
}
|
||||
|
||||
// `meta_item` is the attribute, and `item` is the item being modified.
|
||||
pub trait MultiItemModifier {
|
||||
/// `meta_item` is the attribute, and `item` is the item being modified.
|
||||
fn expand(
|
||||
&self,
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
self.stmt_local(local, sp)
|
||||
}
|
||||
|
||||
// Generates `let _: Type;`, which is usually used for type assertions.
|
||||
/// Generates `let _: Type;`, which is usually used for type assertions.
|
||||
pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
|
||||
let local = P(ast::Local {
|
||||
pat: self.pat_wild(span),
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ fn get_features(
|
|||
features
|
||||
}
|
||||
|
||||
// `cfg_attr`-process the crate's attributes and compute the crate's features.
|
||||
/// `cfg_attr`-process the crate's attributes and compute the crate's features.
|
||||
pub fn features(
|
||||
sess: &Session,
|
||||
mut krate: ast::Crate,
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
krate
|
||||
}
|
||||
|
||||
// Recursively expand all macro invocations in this AST fragment.
|
||||
/// Recursively expand all macro invocations in this AST fragment.
|
||||
pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
|
||||
let orig_expansion_data = self.cx.current_expansion.clone();
|
||||
let orig_force_mode = self.cx.force_mode;
|
||||
|
|
@ -1931,9 +1931,12 @@ pub struct ExpansionConfig<'feat> {
|
|||
pub features: Option<&'feat Features>,
|
||||
pub recursion_limit: Limit,
|
||||
pub trace_mac: bool,
|
||||
pub should_test: bool, // If false, strip `#[test]` nodes
|
||||
pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span`
|
||||
pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics
|
||||
/// If false, strip `#[test]` nodes
|
||||
pub should_test: bool,
|
||||
/// If true, use verbose debugging for `proc_macro::Span`
|
||||
pub span_debug: bool,
|
||||
/// If true, show backtraces for proc-macro panics
|
||||
pub proc_macro_backtrace: bool,
|
||||
}
|
||||
|
||||
impl<'feat> ExpansionConfig<'feat> {
|
||||
|
|
|
|||
|
|
@ -981,8 +981,8 @@ pub struct Pat<'hir> {
|
|||
pub hir_id: HirId,
|
||||
pub kind: PatKind<'hir>,
|
||||
pub span: Span,
|
||||
// Whether to use default binding modes.
|
||||
// At present, this is false only for destructuring assignment.
|
||||
/// Whether to use default binding modes.
|
||||
/// At present, this is false only for destructuring assignment.
|
||||
pub default_binding_modes: bool,
|
||||
}
|
||||
|
||||
|
|
@ -1090,7 +1090,7 @@ impl fmt::Display for RangeEnd {
|
|||
pub struct DotDotPos(u32);
|
||||
|
||||
impl DotDotPos {
|
||||
// Panics if n >= u32::MAX.
|
||||
/// Panics if n >= u32::MAX.
|
||||
pub fn new(n: Option<usize>) -> Self {
|
||||
match n {
|
||||
Some(n) => {
|
||||
|
|
@ -1694,10 +1694,10 @@ impl Expr<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// Whether this looks like a place expr, without checking for deref
|
||||
// adjustments.
|
||||
// This will return `true` in some potentially surprising cases such as
|
||||
// `CONSTANT.field`.
|
||||
/// Whether this looks like a place expr, without checking for deref
|
||||
/// adjustments.
|
||||
/// This will return `true` in some potentially surprising cases such as
|
||||
/// `CONSTANT.field`.
|
||||
pub fn is_syntactic_place_expr(&self) -> bool {
|
||||
self.is_place_expr(|_| true)
|
||||
}
|
||||
|
|
@ -1838,7 +1838,7 @@ impl Expr<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// To a first-order approximation, is this a pattern
|
||||
/// To a first-order approximation, is this a pattern?
|
||||
pub fn is_approximately_pattern(&self) -> bool {
|
||||
match &self.kind {
|
||||
ExprKind::Box(_)
|
||||
|
|
@ -2160,11 +2160,11 @@ impl fmt::Display for LoopIdError {
|
|||
|
||||
#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
|
||||
pub struct Destination {
|
||||
// This is `Some(_)` iff there is an explicit user-specified `label
|
||||
/// This is `Some(_)` iff there is an explicit user-specified 'label
|
||||
pub label: Option<Label>,
|
||||
|
||||
// These errors are caught and then reported during the diagnostics pass in
|
||||
// librustc_passes/loops.rs
|
||||
/// These errors are caught and then reported during the diagnostics pass in
|
||||
/// `librustc_passes/loops.rs`
|
||||
pub target_id: Result<HirId, LoopIdError>,
|
||||
}
|
||||
|
||||
|
|
@ -2335,7 +2335,7 @@ pub enum ImplItemKind<'hir> {
|
|||
Type(&'hir Ty<'hir>),
|
||||
}
|
||||
|
||||
// The name of the associated type for `Fn` return types.
|
||||
/// The name of the associated type for `Fn` return types.
|
||||
pub const FN_OUTPUT_NAME: Symbol = sym::Output;
|
||||
|
||||
/// Bind a type to an associated type (i.e., `A = Foo`).
|
||||
|
|
@ -3261,7 +3261,7 @@ pub enum ForeignItemKind<'hir> {
|
|||
/// A variable captured by a closure.
|
||||
#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
|
||||
pub struct Upvar {
|
||||
// First span where it is accessed (there can be multiple).
|
||||
/// First span where it is accessed (there can be multiple).
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -850,7 +850,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.is_some()
|
||||
}
|
||||
|
||||
// Sets `implicitly_sized` to true on `Bounds` if necessary
|
||||
/// Sets `implicitly_sized` to true on `Bounds` if necessary
|
||||
pub(crate) fn add_implicitly_sized<'hir>(
|
||||
&self,
|
||||
bounds: &mut Bounds<'hir>,
|
||||
|
|
@ -2391,7 +2391,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
path_segs
|
||||
}
|
||||
|
||||
// Check a type `Path` and convert it to a `Ty`.
|
||||
/// Check a type `Path` and convert it to a `Ty`.
|
||||
pub fn res_to_ty(
|
||||
&self,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -233,9 +233,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
|||
result
|
||||
}
|
||||
|
||||
// This is an implementation of the TypeRelation trait with the
|
||||
// aim of simply comparing for equality (without side-effects).
|
||||
// It is not intended to be used anywhere else other than here.
|
||||
/// This is an implementation of the [`TypeRelation`] trait with the
|
||||
/// aim of simply comparing for equality (without side-effects).
|
||||
///
|
||||
/// It is not intended to be used anywhere else other than here.
|
||||
pub(crate) struct SimpleEqRelation<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -42,22 +42,22 @@ impl<'a> fmt::Debug for VarianceTerm<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// The first pass over the crate simply builds up the set of inferreds.
|
||||
/// The first pass over the crate simply builds up the set of inferreds.
|
||||
|
||||
pub struct TermsContext<'a, 'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
pub arena: &'a DroplessArena,
|
||||
|
||||
// For marker types, UnsafeCell, and other lang items where
|
||||
// variance is hardcoded, records the item-id and the hardcoded
|
||||
// variance.
|
||||
/// For marker types, `UnsafeCell`, and other lang items where
|
||||
/// variance is hardcoded, records the item-id and the hardcoded
|
||||
/// variance.
|
||||
pub lang_items: Vec<(LocalDefId, Vec<ty::Variance>)>,
|
||||
|
||||
// Maps from the node id of an item to the first inferred index
|
||||
// used for its type & region parameters.
|
||||
/// Maps from the node id of an item to the first inferred index
|
||||
/// used for its type & region parameters.
|
||||
pub inferred_starts: LocalDefIdMap<InferredIndex>,
|
||||
|
||||
// Maps from an InferredIndex to the term for that variable.
|
||||
/// Maps from an InferredIndex to the term for that variable.
|
||||
pub inferred_terms: Vec<VarianceTermPtr<'a>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||
}
|
||||
|
||||
// Requires that the two types unify, and prints an error message if
|
||||
// they don't.
|
||||
/// Requires that the two types unify, and prints an error message if
|
||||
/// they don't.
|
||||
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
|
||||
if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
|
||||
e.emit();
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ impl<'a, 'tcx> Expectation<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Resolves `expected` by a single level if it is a variable. If
|
||||
// there is no expected type or resolution is not possible (e.g.,
|
||||
// no constraints yet present), just returns `self`.
|
||||
/// Resolves `expected` by a single level if it is a variable. If
|
||||
/// there is no expected type or resolution is not possible (e.g.,
|
||||
/// no constraints yet present), just returns `self`.
|
||||
fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
|
||||
match self {
|
||||
NoExpectation => NoExpectation,
|
||||
|
|
|
|||
|
|
@ -914,8 +914,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Check if an expression `original_expr_id` comes from the condition of a while loop,
|
||||
// as opposed from the body of a while loop, which we can naively check by iterating
|
||||
// parents until we find a loop...
|
||||
/// as opposed from the body of a while loop, which we can naively check by iterating
|
||||
/// parents until we find a loop...
|
||||
pub(super) fn comes_from_while_condition(
|
||||
&self,
|
||||
original_expr_id: HirId,
|
||||
|
|
|
|||
|
|
@ -38,19 +38,19 @@ pub struct Inherited<'tcx> {
|
|||
|
||||
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
|
||||
|
||||
// Some additional `Sized` obligations badly affect type inference.
|
||||
// These obligations are added in a later stage of typeck.
|
||||
// Removing these may also cause additional complications, see #101066.
|
||||
/// Some additional `Sized` obligations badly affect type inference.
|
||||
/// These obligations are added in a later stage of typeck.
|
||||
/// Removing these may also cause additional complications, see #101066.
|
||||
pub(super) deferred_sized_obligations:
|
||||
RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>,
|
||||
|
||||
// When we process a call like `c()` where `c` is a closure type,
|
||||
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
|
||||
// `FnOnce` closure. In that case, we defer full resolution of the
|
||||
// call until upvar inference can kick in and make the
|
||||
// decision. We keep these deferred resolutions grouped by the
|
||||
// def-id of the closure, so that once we decide, we can easily go
|
||||
// back and process them.
|
||||
/// When we process a call like `c()` where `c` is a closure type,
|
||||
/// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
|
||||
/// `FnOnce` closure. In that case, we defer full resolution of the
|
||||
/// call until upvar inference can kick in and make the
|
||||
/// decision. We keep these deferred resolutions grouped by the
|
||||
/// def-id of the closure, so that once we decide, we can easily go
|
||||
/// back and process them.
|
||||
pub(super) deferred_call_resolutions: RefCell<LocalDefIdMap<Vec<DeferredCallResolution<'tcx>>>>,
|
||||
|
||||
pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
|
||||
|
|
|
|||
|
|
@ -438,9 +438,9 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
// A visitor that collects all #[rustc_clean] attributes from
|
||||
// the HIR. It is used to verify that we really ran checks for all annotated
|
||||
// nodes.
|
||||
/// A visitor that collects all `#[rustc_clean]` attributes from
|
||||
/// the HIR. It is used to verify that we really ran checks for all annotated
|
||||
/// nodes.
|
||||
pub struct FindAllAttrs<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
found_attrs: Vec<&'tcx Attribute>,
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FreeRegionMap<'tcx> {
|
||||
// Stores the relation `a < b`, where `a` and `b` are regions.
|
||||
//
|
||||
// Invariant: only free regions like `'x` or `'static` are stored
|
||||
// in this relation, not scopes.
|
||||
/// Stores the relation `a < b`, where `a` and `b` are regions.
|
||||
///
|
||||
/// Invariant: only free regions like `'x` or `'static` are stored
|
||||
/// in this relation, not scopes.
|
||||
pub(crate) relation: TransitiveRelation<Region<'tcx>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -410,19 +410,19 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Visitor that requires that (almost) all regions in the type visited outlive
|
||||
// `least_region`. We cannot use `push_outlives_components` because regions in
|
||||
// closure signatures are not included in their outlives components. We need to
|
||||
// ensure all regions outlive the given bound so that we don't end up with,
|
||||
// say, `ReVar` appearing in a return type and causing ICEs when other
|
||||
// functions end up with region constraints involving regions from other
|
||||
// functions.
|
||||
//
|
||||
// We also cannot use `for_each_free_region` because for closures it includes
|
||||
// the regions parameters from the enclosing item.
|
||||
//
|
||||
// We ignore any type parameters because impl trait values are assumed to
|
||||
// capture all the in-scope type parameters.
|
||||
/// Visitor that requires that (almost) all regions in the type visited outlive
|
||||
/// `least_region`. We cannot use `push_outlives_components` because regions in
|
||||
/// closure signatures are not included in their outlives components. We need to
|
||||
/// ensure all regions outlive the given bound so that we don't end up with,
|
||||
/// say, `ReVar` appearing in a return type and causing ICEs when other
|
||||
/// functions end up with region constraints involving regions from other
|
||||
/// functions.
|
||||
///
|
||||
/// We also cannot use `for_each_free_region` because for closures it includes
|
||||
/// the regions parameters from the enclosing item.
|
||||
///
|
||||
/// We ignore any type parameters because impl trait values are assumed to
|
||||
/// capture all the in-scope type parameters.
|
||||
pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
pub op: OP,
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ use super::{OpaqueTypeDecl, OpaqueTypeMap};
|
|||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct OpaqueTypeStorage<'tcx> {
|
||||
// Opaque types found in explicit return types and their
|
||||
// associated fresh inference variable. Writeback resolves these
|
||||
// variables to get the concrete type, which can be used to
|
||||
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
|
||||
/// Opaque types found in explicit return types and their
|
||||
/// associated fresh inference variable. Writeback resolves these
|
||||
/// variables to get the concrete type, which can be used to
|
||||
/// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
|
||||
pub opaque_types: OpaqueTypeMap<'tcx>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ impl LintStore {
|
|||
self.late_module_passes.push(Box::new(pass));
|
||||
}
|
||||
|
||||
// Helper method for register_early/late_pass
|
||||
/// Helper method for register_early/late_pass
|
||||
pub fn register_lints(&mut self, lints: &[&'static Lint]) {
|
||||
for lint in lints {
|
||||
self.lints.push(lint);
|
||||
|
|
|
|||
|
|
@ -67,10 +67,10 @@ impl std::ops::Deref for MetadataBlob {
|
|||
}
|
||||
}
|
||||
|
||||
// A map from external crate numbers (as decoded from some crate file) to
|
||||
// local crate numbers (as generated during this session). Each external
|
||||
// crate may refer to types in other external crates, and each has their
|
||||
// own crate numbers.
|
||||
/// A map from external crate numbers (as decoded from some crate file) to
|
||||
/// local crate numbers (as generated during this session). Each external
|
||||
/// crate may refer to types in other external crates, and each has their
|
||||
/// own crate numbers.
|
||||
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
|
||||
|
||||
pub(crate) struct CrateMetadata {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ use super::{
|
|||
/// Represents the result of const evaluation via the `eval_to_allocation` query.
|
||||
#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct ConstAlloc<'tcx> {
|
||||
// the value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
|
||||
// (so you can use `AllocMap::unwrap_memory`).
|
||||
/// The value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
|
||||
/// (so you can use `AllocMap::unwrap_memory`).
|
||||
pub alloc_id: AllocId,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ pub struct ImplDerivedObligationCause<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> ObligationCauseCode<'tcx> {
|
||||
// Return the base obligation, ignoring derived obligations.
|
||||
/// Returns the base obligation, ignoring derived obligations.
|
||||
pub fn peel_derives(&self) -> &Self {
|
||||
let mut base_cause = self;
|
||||
while let Some((parent_code, _)) = base_cause.parent() {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use super::{Ty, TyCtxt};
|
|||
|
||||
use self::BorrowKind::*;
|
||||
|
||||
// Captures are represented using fields inside a structure.
|
||||
// This represents accessing self in the closure structure
|
||||
/// Captures are represented using fields inside a structure.
|
||||
/// This represents accessing self in the closure structure
|
||||
pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
|
||||
|
|
@ -91,7 +91,7 @@ pub enum ClosureKind {
|
|||
}
|
||||
|
||||
impl<'tcx> ClosureKind {
|
||||
// This is the initial value used when doing upvar inference.
|
||||
/// This is the initial value used when doing upvar inference.
|
||||
pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
|
||||
|
||||
/// Returns `true` if a type that impls this closure kind
|
||||
|
|
|
|||
|
|
@ -713,22 +713,24 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
self.node_substs.get(&id.local_id).cloned()
|
||||
}
|
||||
|
||||
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
|
||||
// doesn't provide type parameter substitutions.
|
||||
/// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function
|
||||
/// doesn't provide type parameter substitutions.
|
||||
///
|
||||
/// [`expr_ty`]: TypeckResults::expr_ty
|
||||
pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> {
|
||||
self.node_type(pat.hir_id)
|
||||
}
|
||||
|
||||
// Returns the type of an expression as a monotype.
|
||||
//
|
||||
// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
|
||||
// some cases, we insert `Adjustment` annotations such as auto-deref or
|
||||
// auto-ref. The type returned by this function does not consider such
|
||||
// adjustments. See `expr_ty_adjusted()` instead.
|
||||
//
|
||||
// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
|
||||
// ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize"
|
||||
// instead of "fn(ty) -> T with T = isize".
|
||||
/// Returns the type of an expression as a monotype.
|
||||
///
|
||||
/// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in
|
||||
/// some cases, we insert `Adjustment` annotations such as auto-deref or
|
||||
/// auto-ref. The type returned by this function does not consider such
|
||||
/// adjustments. See `expr_ty_adjusted()` instead.
|
||||
///
|
||||
/// NB (2): This type doesn't provide type parameter substitutions; e.g., if you
|
||||
/// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize`
|
||||
/// instead of `fn(ty) -> T with T = isize`.
|
||||
pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> {
|
||||
self.node_type(expr.hir_id)
|
||||
}
|
||||
|
|
@ -995,15 +997,15 @@ impl<'tcx> CommonConsts<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime
|
||||
// conflict.
|
||||
/// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime
|
||||
/// conflict.
|
||||
#[derive(Debug)]
|
||||
pub struct FreeRegionInfo {
|
||||
// `LocalDefId` corresponding to FreeRegion
|
||||
/// `LocalDefId` corresponding to FreeRegion
|
||||
pub def_id: LocalDefId,
|
||||
// the bound region corresponding to FreeRegion
|
||||
/// the bound region corresponding to FreeRegion
|
||||
pub boundregion: ty::BoundRegionKind,
|
||||
// checks if bound region is in Impl Item
|
||||
/// checks if bound region is in Impl Item
|
||||
pub is_impl_item: bool,
|
||||
}
|
||||
|
||||
|
|
@ -1660,7 +1662,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Checks if the bound region is in Impl Item.
|
||||
/// Checks if the bound region is in Impl Item.
|
||||
pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool {
|
||||
let container_id = self.parent(suitable_region_binding_scope.to_def_id());
|
||||
if self.impl_trait_ref(container_id).is_some() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::slice;
|
|||
pub struct FlagComputation {
|
||||
pub flags: TypeFlags,
|
||||
|
||||
// see `Ty::outer_exclusive_binder` for details
|
||||
/// see `Ty::outer_exclusive_binder` for details
|
||||
pub outer_exclusive_binder: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ impl Visibility<DefId> {
|
|||
self.map_id(|id| id.expect_local())
|
||||
}
|
||||
|
||||
// Returns `true` if this item is visible anywhere in the local crate.
|
||||
/// Returns `true` if this item is visible anywhere in the local crate.
|
||||
pub fn is_visible_locally(self) -> bool {
|
||||
match self {
|
||||
Visibility::Public => true,
|
||||
|
|
@ -926,9 +926,10 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// `A: B`
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
|
||||
pub struct OutlivesPredicate<A, B>(pub A, pub B);
|
||||
pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
|
||||
pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
|
||||
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
|
||||
|
|
|
|||
|
|
@ -2243,7 +2243,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// If `self` is a primitive, return its [`Symbol`].
|
||||
/// If `self` is a primitive, return its [`Symbol`].
|
||||
pub fn primitive_symbol(self) -> Option<Symbol> {
|
||||
match self.kind() {
|
||||
ty::Bool => Some(sym::bool),
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Query provider for `trait_impls_of`.
|
||||
/// Query provider for `trait_impls_of`.
|
||||
pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls {
|
||||
let mut impls = TraitImpls::default();
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
|
|||
impls
|
||||
}
|
||||
|
||||
// Query provider for `incoherent_impls`.
|
||||
/// Query provider for `incoherent_impls`.
|
||||
pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
|
||||
let mut impls = Vec::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -1208,11 +1208,11 @@ pub fn is_trivially_const_drop<'tcx>(ty: Ty<'tcx>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Does the equivalent of
|
||||
// ```
|
||||
// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
|
||||
// folder.tcx().intern_*(&v)
|
||||
// ```
|
||||
/// Does the equivalent of
|
||||
/// ```ignore (ilustrative)
|
||||
/// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
|
||||
/// folder.tcx().intern_*(&v)
|
||||
/// ```
|
||||
pub fn fold_list<'tcx, F, T>(
|
||||
list: &'tcx ty::List<T>,
|
||||
folder: &mut F,
|
||||
|
|
|
|||
|
|
@ -2,35 +2,35 @@ use rustc_middle::thir::*;
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) enum Category {
|
||||
// An assignable memory location like `x`, `x.f`, `foo()[3]`, that
|
||||
// sort of thing. Something that could appear on the LHS of an `=`
|
||||
// sign.
|
||||
/// An assignable memory location like `x`, `x.f`, `foo()[3]`, that
|
||||
/// sort of thing. Something that could appear on the LHS of an `=`
|
||||
/// sign.
|
||||
Place,
|
||||
|
||||
// A literal like `23` or `"foo"`. Does not include constant
|
||||
// expressions like `3 + 5`.
|
||||
/// A literal like `23` or `"foo"`. Does not include constant
|
||||
/// expressions like `3 + 5`.
|
||||
Constant,
|
||||
|
||||
// Something that generates a new value at runtime, like `x + y`
|
||||
// or `foo()`.
|
||||
/// Something that generates a new value at runtime, like `x + y`
|
||||
/// or `foo()`.
|
||||
Rvalue(RvalueFunc),
|
||||
}
|
||||
|
||||
// Rvalues fall into different "styles" that will determine which fn
|
||||
// is best suited to generate them.
|
||||
/// Rvalues fall into different "styles" that will determine which fn
|
||||
/// is best suited to generate them.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) enum RvalueFunc {
|
||||
// Best generated by `into`. This is generally exprs that
|
||||
// cause branching, like `match`, but also includes calls.
|
||||
/// Best generated by `into`. This is generally exprs that
|
||||
/// cause branching, like `match`, but also includes calls.
|
||||
Into,
|
||||
|
||||
// Best generated by `as_rvalue`. This is usually the case.
|
||||
/// Best generated by `as_rvalue`. This is usually the case.
|
||||
AsRvalue,
|
||||
}
|
||||
|
||||
/// Determines the category for a given expression. Note that scope
|
||||
/// and paren expressions have no category.
|
||||
impl Category {
|
||||
/// Determines the category for a given expression. Note that scope
|
||||
/// and paren expressions have no category.
|
||||
pub(crate) fn of(ek: &ExprKind<'_>) -> Option<Category> {
|
||||
match *ek {
|
||||
ExprKind::Scope { .. } => None,
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Operand::Constant(constant)
|
||||
}
|
||||
|
||||
// Returns a zero literal operand for the appropriate type, works for
|
||||
// bool, char and integers.
|
||||
/// Returns a zero literal operand for the appropriate type, works for
|
||||
/// bool, char and integers.
|
||||
pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||
|
||||
|
|
|
|||
|
|
@ -443,8 +443,9 @@ impl<'tcx> Scopes<'tcx> {
|
|||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// Adding and removing scopes
|
||||
// ==========================
|
||||
// Start a breakable scope, which tracks where `continue`, `break` and
|
||||
// `return` should branch to.
|
||||
|
||||
/// Start a breakable scope, which tracks where `continue`, `break` and
|
||||
/// `return` should branch to.
|
||||
pub(crate) fn in_breakable_scope<F>(
|
||||
&mut self,
|
||||
loop_block: Option<BasicBlock>,
|
||||
|
|
@ -799,6 +800,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
// Finding scopes
|
||||
// ==============
|
||||
|
||||
/// Returns the scope that we should use as the lifetime of an
|
||||
/// operand. Basically, an operand must live until it is consumed.
|
||||
/// This is similar to, but not quite the same as, the temporary
|
||||
|
|
@ -824,6 +826,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
// Scheduling drops
|
||||
// ================
|
||||
|
||||
pub(crate) fn schedule_drop_storage_and_value(
|
||||
&mut self,
|
||||
span: Span,
|
||||
|
|
@ -996,6 +999,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
// Other
|
||||
// =====
|
||||
|
||||
/// Returns the [DropIdx] for the innermost drop if the function unwound at
|
||||
/// this point. The `DropIdx` will be created if it doesn't already exist.
|
||||
fn diverge_cleanup(&mut self) -> DropIdx {
|
||||
|
|
|
|||
|
|
@ -5,37 +5,36 @@ use crate::util;
|
|||
use crate::MirPass;
|
||||
use rustc_middle::mir::patch::MirPatch;
|
||||
|
||||
// This pass moves values being dropped that are within a packed
|
||||
// struct to a separate local before dropping them, to ensure that
|
||||
// they are dropped from an aligned address.
|
||||
//
|
||||
// For example, if we have something like
|
||||
// ```Rust
|
||||
// #[repr(packed)]
|
||||
// struct Foo {
|
||||
// dealign: u8,
|
||||
// data: Vec<u8>
|
||||
// }
|
||||
//
|
||||
// let foo = ...;
|
||||
// ```
|
||||
//
|
||||
// We want to call `drop_in_place::<Vec<u8>>` on `data` from an aligned
|
||||
// address. This means we can't simply drop `foo.data` directly, because
|
||||
// its address is not aligned.
|
||||
//
|
||||
// Instead, we move `foo.data` to a local and drop that:
|
||||
// ```
|
||||
// storage.live(drop_temp)
|
||||
// drop_temp = foo.data;
|
||||
// drop(drop_temp) -> next
|
||||
// next:
|
||||
// storage.dead(drop_temp)
|
||||
// ```
|
||||
//
|
||||
// The storage instructions are required to avoid stack space
|
||||
// blowup.
|
||||
|
||||
/// This pass moves values being dropped that are within a packed
|
||||
/// struct to a separate local before dropping them, to ensure that
|
||||
/// they are dropped from an aligned address.
|
||||
///
|
||||
/// For example, if we have something like
|
||||
/// ```ignore (ilustrative)
|
||||
/// #[repr(packed)]
|
||||
/// struct Foo {
|
||||
/// dealign: u8,
|
||||
/// data: Vec<u8>
|
||||
/// }
|
||||
///
|
||||
/// let foo = ...;
|
||||
/// ```
|
||||
///
|
||||
/// We want to call `drop_in_place::<Vec<u8>>` on `data` from an aligned
|
||||
/// address. This means we can't simply drop `foo.data` directly, because
|
||||
/// its address is not aligned.
|
||||
///
|
||||
/// Instead, we move `foo.data` to a local and drop that:
|
||||
/// ```ignore (ilustrative)
|
||||
/// storage.live(drop_temp)
|
||||
/// drop_temp = foo.data;
|
||||
/// drop(drop_temp) -> next
|
||||
/// next:
|
||||
/// storage.dead(drop_temp)
|
||||
/// ```
|
||||
///
|
||||
/// The storage instructions are required to avoid stack space
|
||||
/// blowup.
|
||||
pub struct AddMovesForPackedDrops;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub fn build_ptr_tys<'tcx>(
|
|||
(unique_ty, nonnull_ty, ptr_ty)
|
||||
}
|
||||
|
||||
// Constructs the projection needed to access a Box's pointer
|
||||
/// Constructs the projection needed to access a Box's pointer
|
||||
pub fn build_projection<'tcx>(
|
||||
unique_ty: Ty<'tcx>,
|
||||
nonnull_ty: Ty<'tcx>,
|
||||
|
|
|
|||
|
|
@ -295,8 +295,8 @@ impl<'tcx> InliningMap<'tcx> {
|
|||
assert!(self.index.insert(source, start_index..end_index).is_none());
|
||||
}
|
||||
|
||||
// Internally iterate over all items referenced by `source` which will be
|
||||
// made available for inlining.
|
||||
/// Internally iterate over all items referenced by `source` which will be
|
||||
/// made available for inlining.
|
||||
pub fn with_inlining_candidates<F>(&self, source: MonoItem<'tcx>, mut f: F)
|
||||
where
|
||||
F: FnMut(MonoItem<'tcx>),
|
||||
|
|
@ -310,7 +310,7 @@ impl<'tcx> InliningMap<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Internally iterate over all items and the things each accesses.
|
||||
/// Internally iterate over all items and the things each accesses.
|
||||
pub fn iter_accesses<F>(&self, mut f: F)
|
||||
where
|
||||
F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Characters and their corresponding confusables were collected from
|
||||
// https://www.unicode.org/Public/security/10.0.0/confusables.txt
|
||||
//! Characters and their corresponding confusables were collected from
|
||||
//! <https://www.unicode.org/Public/security/10.0.0/confusables.txt>
|
||||
|
||||
use super::StringReader;
|
||||
use crate::token::{self, Delimiter};
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ impl AttrWrapper {
|
|||
self.attrs
|
||||
}
|
||||
|
||||
// Prepend `self.attrs` to `attrs`.
|
||||
/// Prepend `self.attrs` to `attrs`.
|
||||
// FIXME: require passing an NT to prevent misuse of this method
|
||||
pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) {
|
||||
let mut self_attrs = self.attrs;
|
||||
|
|
|
|||
|
|
@ -224,9 +224,9 @@ impl MultiSugg {
|
|||
}
|
||||
}
|
||||
|
||||
// SnapshotParser is used to create a snapshot of the parser
|
||||
// without causing duplicate errors being emitted when the `Parser`
|
||||
// is dropped.
|
||||
/// SnapshotParser is used to create a snapshot of the parser
|
||||
/// without causing duplicate errors being emitted when the `Parser`
|
||||
/// is dropped.
|
||||
pub struct SnapshotParser<'a> {
|
||||
parser: Parser<'a>,
|
||||
unclosed_delims: Vec<UnmatchedBrace>,
|
||||
|
|
|
|||
|
|
@ -779,26 +779,26 @@ impl<K: DepKind> DepGraph<K> {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns true if the given node has been marked as red during the
|
||||
// current compilation session. Used in various assertions
|
||||
/// Returns true if the given node has been marked as red during the
|
||||
/// current compilation session. Used in various assertions
|
||||
pub fn is_red(&self, dep_node: &DepNode<K>) -> bool {
|
||||
self.node_color(dep_node) == Some(DepNodeColor::Red)
|
||||
}
|
||||
|
||||
// Returns true if the given node has been marked as green during the
|
||||
// current compilation session. Used in various assertions
|
||||
/// Returns true if the given node has been marked as green during the
|
||||
/// current compilation session. Used in various assertions
|
||||
pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
|
||||
self.node_color(dep_node).map_or(false, |c| c.is_green())
|
||||
}
|
||||
|
||||
// This method loads all on-disk cacheable query results into memory, so
|
||||
// they can be written out to the new cache file again. Most query results
|
||||
// will already be in memory but in the case where we marked something as
|
||||
// green but then did not need the value, that value will never have been
|
||||
// loaded from disk.
|
||||
//
|
||||
// This method will only load queries that will end up in the disk cache.
|
||||
// Other queries will not be executed.
|
||||
/// This method loads all on-disk cacheable query results into memory, so
|
||||
/// they can be written out to the new cache file again. Most query results
|
||||
/// will already be in memory but in the case where we marked something as
|
||||
/// green but then did not need the value, that value will never have been
|
||||
/// loaded from disk.
|
||||
///
|
||||
/// This method will only load queries that will end up in the disk cache.
|
||||
/// Other queries will not be executed.
|
||||
pub fn exec_cache_promotions<Tcx: DepContext<DepKind = K>>(&self, tcx: Tcx) {
|
||||
let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ pub(crate) struct NameResolution<'a> {
|
|||
}
|
||||
|
||||
impl<'a> NameResolution<'a> {
|
||||
// Returns the binding for the name if it is known or None if it not known.
|
||||
/// Returns the binding for the name if it is known or None if it not known.
|
||||
pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> {
|
||||
self.binding.and_then(|binding| {
|
||||
if !binding.is_glob_import() || self.single_imports.is_empty() {
|
||||
|
|
@ -228,8 +228,8 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi
|
|||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
// Given a binding and an import that resolves to it,
|
||||
// return the corresponding binding defined by the import.
|
||||
/// Given a binding and an import that resolves to it,
|
||||
/// return the corresponding binding defined by the import.
|
||||
pub(crate) fn import(
|
||||
&self,
|
||||
binding: &'a NameBinding<'a>,
|
||||
|
|
@ -261,7 +261,7 @@ impl<'a> Resolver<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
// Define the name or return the existing binding if there is a collision.
|
||||
/// Define the name or return the existing binding if there is a collision.
|
||||
pub(crate) fn try_define(
|
||||
&mut self,
|
||||
module: Module<'a>,
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl<'tcx> SaveContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns path to the compilation output (e.g., libfoo-12345678.rmeta)
|
||||
/// Returns path to the compilation output (e.g., libfoo-12345678.rmeta)
|
||||
pub fn compilation_output(&self, crate_name: &str) -> PathBuf {
|
||||
let sess = &self.tcx.sess;
|
||||
// Save-analysis is emitted per whole session, not per each crate type
|
||||
|
|
@ -112,7 +112,7 @@ impl<'tcx> SaveContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// List external crates used by the current crate.
|
||||
/// List external crates used by the current crate.
|
||||
pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
|
||||
let mut result = Vec::with_capacity(self.tcx.crates(()).len());
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ macro_rules! max_leb128_len {
|
|||
};
|
||||
}
|
||||
|
||||
// Returns the longest LEB128 encoding of all supported integer types.
|
||||
/// Returns the longest LEB128 encoding of all supported integer types.
|
||||
pub const fn max_leb128_len() -> usize {
|
||||
max_leb128_len!(u128)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,19 +155,19 @@ impl Encoder for MemEncoder {
|
|||
|
||||
pub type FileEncodeResult = Result<usize, io::Error>;
|
||||
|
||||
// `FileEncoder` encodes data to file via fixed-size buffer.
|
||||
//
|
||||
// When encoding large amounts of data to a file, using `FileEncoder` may be
|
||||
// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the
|
||||
// `Vec` to file, as the latter uses as much memory as there is encoded data,
|
||||
// while the former uses the fixed amount of memory allocated to the buffer.
|
||||
// `FileEncoder` also has the advantage of not needing to reallocate as data
|
||||
// is appended to it, but the disadvantage of requiring more error handling,
|
||||
// which has some runtime overhead.
|
||||
/// `FileEncoder` encodes data to file via fixed-size buffer.
|
||||
///
|
||||
/// When encoding large amounts of data to a file, using `FileEncoder` may be
|
||||
/// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the
|
||||
/// `Vec` to file, as the latter uses as much memory as there is encoded data,
|
||||
/// while the former uses the fixed amount of memory allocated to the buffer.
|
||||
/// `FileEncoder` also has the advantage of not needing to reallocate as data
|
||||
/// is appended to it, but the disadvantage of requiring more error handling,
|
||||
/// which has some runtime overhead.
|
||||
pub struct FileEncoder {
|
||||
// The input buffer. For adequate performance, we need more control over
|
||||
// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
|
||||
// buffer access API, we can use it, and remove `buf` and `buffered`.
|
||||
/// The input buffer. For adequate performance, we need more control over
|
||||
/// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
|
||||
/// buffer access API, we can use it, and remove `buf` and `buffered`.
|
||||
buf: Box<[MaybeUninit<u8>]>,
|
||||
buffered: usize,
|
||||
flushed: usize,
|
||||
|
|
@ -711,7 +711,7 @@ impl<'a> Decodable<MemDecoder<'a>> for Vec<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
// An integer that will always encode to 8 bytes.
|
||||
/// An integer that will always encode to 8 bytes.
|
||||
pub struct IntEncodedWithFixedSize(pub u64);
|
||||
|
||||
impl IntEncodedWithFixedSize {
|
||||
|
|
|
|||
|
|
@ -78,10 +78,10 @@ use sha2::Sha256;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// Per-session global variables: this struct is stored in thread-local storage
|
||||
// in such a way that it is accessible without any kind of handle to all
|
||||
// threads within the compilation session, but is not accessible outside the
|
||||
// session.
|
||||
/// Per-session global variables: this struct is stored in thread-local storage
|
||||
/// in such a way that it is accessible without any kind of handle to all
|
||||
/// threads within the compilation session, but is not accessible outside the
|
||||
/// session.
|
||||
pub struct SessionGlobals {
|
||||
symbol_interner: symbol::Interner,
|
||||
span_interner: Lock<span_encoding::SpanInterner>,
|
||||
|
|
@ -359,8 +359,8 @@ impl FileName {
|
|||
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
|
||||
}
|
||||
|
||||
// This may include transient local filesystem information.
|
||||
// Must not be embedded in build outputs.
|
||||
/// This may include transient local filesystem information.
|
||||
/// Must not be embedded in build outputs.
|
||||
pub fn prefer_local(&self) -> FileNameDisplay<'_> {
|
||||
FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
|
||||
}
|
||||
|
|
@ -751,7 +751,7 @@ impl Span {
|
|||
|
||||
/// Checks if a span is "internal" to a macro in which `unsafe`
|
||||
/// can be used without triggering the `unsafe_code` lint.
|
||||
// (that is, a macro marked with `#[allow_internal_unsafe]`).
|
||||
/// (that is, a macro marked with `#[allow_internal_unsafe]`).
|
||||
pub fn allows_unsafe(self) -> bool {
|
||||
self.ctxt().outer_expn_data().allow_internal_unsafe
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,14 +130,14 @@ impl FileLoader for RealFileLoader {
|
|||
/// different has no real downsides.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
|
||||
pub struct StableSourceFileId {
|
||||
// A hash of the source file's FileName. This is hash so that it's size
|
||||
// is more predictable than if we included the actual FileName value.
|
||||
/// A hash of the source file's [`FileName`]. This is hash so that it's size
|
||||
/// is more predictable than if we included the actual [`FileName`] value.
|
||||
pub file_name_hash: u64,
|
||||
|
||||
// The CrateNum of the crate this source file was originally parsed for.
|
||||
// We cannot include this information in the hash because at the time
|
||||
// of hashing we don't have the context to map from the CrateNum's numeric
|
||||
// value to a StableCrateId.
|
||||
/// The [`CrateNum`] of the crate this source file was originally parsed for.
|
||||
/// We cannot include this information in the hash because at the time
|
||||
/// of hashing we don't have the context to map from the [`CrateNum`]'s numeric
|
||||
/// value to a `StableCrateId`.
|
||||
pub cnum: CrateNum,
|
||||
}
|
||||
|
||||
|
|
@ -402,7 +402,7 @@ impl SourceMap {
|
|||
source_file
|
||||
}
|
||||
|
||||
// If there is a doctest offset, applies it to the line.
|
||||
/// If there is a doctest offset, applies it to the line.
|
||||
pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
|
||||
match file {
|
||||
FileName::DocTest(_, offset) => {
|
||||
|
|
@ -429,7 +429,7 @@ impl SourceMap {
|
|||
Loc { file: sf, line, col, col_display }
|
||||
}
|
||||
|
||||
// If the corresponding `SourceFile` is empty, does not return a line number.
|
||||
/// If the corresponding `SourceFile` is empty, does not return a line number.
|
||||
pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceFile>> {
|
||||
let f = self.lookup_source_file(pos);
|
||||
|
||||
|
|
@ -1053,9 +1053,9 @@ impl SourceMap {
|
|||
SourceFileAndBytePos { sf, pos: offset }
|
||||
}
|
||||
|
||||
// Returns the index of the `SourceFile` (in `self.files`) that contains `pos`.
|
||||
// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
|
||||
// since `source_files` is a `MonotonicVec`
|
||||
/// Returns the index of the [`SourceFile`] (in `self.files`) that contains `pos`.
|
||||
/// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
|
||||
/// since `source_files` is a `MonotonicVec`
|
||||
pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize {
|
||||
self.files
|
||||
.borrow()
|
||||
|
|
|
|||
|
|
@ -2051,8 +2051,8 @@ impl Symbol {
|
|||
}
|
||||
|
||||
impl Ident {
|
||||
// Returns `true` for reserved identifiers used internally for elided lifetimes,
|
||||
// unnamed method parameters, crate root module, error recovery etc.
|
||||
/// Returns `true` for reserved identifiers used internally for elided lifetimes,
|
||||
/// unnamed method parameters, crate root module, error recovery etc.
|
||||
pub fn is_special(self) -> bool {
|
||||
self.name.is_special()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1650,9 +1650,9 @@ pub struct TargetOptions {
|
|||
|
||||
/// Flag indicating whether #[thread_local] is available for this target.
|
||||
pub has_thread_local: bool,
|
||||
// This is mainly for easy compatibility with emscripten.
|
||||
// If we give emcc .o files that are actually .bc files it
|
||||
// will 'just work'.
|
||||
/// This is mainly for easy compatibility with emscripten.
|
||||
/// If we give emcc .o files that are actually .bc files it
|
||||
/// will 'just work'.
|
||||
pub obj_is_bitcode: bool,
|
||||
/// Whether the target requires that emitted object code includes bitcode.
|
||||
pub forces_embed_bitcode: bool,
|
||||
|
|
@ -1792,12 +1792,12 @@ pub struct TargetOptions {
|
|||
/// since this is most common among tier 1 and tier 2 targets.
|
||||
pub supports_stack_protector: bool,
|
||||
|
||||
// The name of entry function.
|
||||
// Default value is "main"
|
||||
/// The name of entry function.
|
||||
/// Default value is "main"
|
||||
pub entry_name: StaticCow<str>,
|
||||
|
||||
// The ABI of entry function.
|
||||
// Default value is `Conv::C`, i.e. C call convention
|
||||
/// The ABI of entry function.
|
||||
/// Default value is `Conv::C`, i.e. C call convention
|
||||
pub entry_abi: Conv,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -861,7 +861,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Replaces all ReVars in a type with ty::Region's, using the provided map
|
||||
/// Replaces all ReVars in a type with ty::Region's, using the provided map
|
||||
pub struct RegionReplacer<'a, 'tcx> {
|
||||
vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -829,7 +829,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
|
||||
/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
|
||||
pub struct PlaceholderReplacer<'me, 'tcx> {
|
||||
infcx: &'me InferCtxt<'tcx>,
|
||||
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ fn fulfill_implication<'tcx>(
|
|||
Ok(infcx.resolve_vars_if_possible(target_substs))
|
||||
}
|
||||
|
||||
// Query provider for `specialization_graph_of`.
|
||||
/// Query provider for `specialization_graph_of`.
|
||||
pub(super) fn specialization_graph_provider(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_id: DefId,
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ impl From<DefId> for ItemId {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Crate {
|
||||
pub(crate) module: Item,
|
||||
pub(crate) primitives: ThinVec<(DefId, PrimitiveType)>,
|
||||
/// Only here so that they can be filtered through the rustdoc passes.
|
||||
pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
|
||||
}
|
||||
|
|
@ -2572,7 +2571,7 @@ mod size_asserts {
|
|||
use super::*;
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(Crate, 72); // frequently moved by-value
|
||||
static_assert_size!(Crate, 64); // frequently moved by-value
|
||||
static_assert_size!(DocFragment, 32);
|
||||
static_assert_size!(GenericArg, 32);
|
||||
static_assert_size!(GenericArgs, 32);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
|||
}));
|
||||
}
|
||||
|
||||
Crate { module, primitives, external_traits: cx.external_traits.clone() }
|
||||
Crate { module, external_traits: cx.external_traits.clone() }
|
||||
}
|
||||
|
||||
pub(crate) fn substs_to_args<'tcx>(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::formats::cache::Cache;
|
|||
use crate::visit::DocVisitor;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_middle::ty::{self, DefIdTree};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
|
|
@ -25,7 +25,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
|
|||
synth.impls
|
||||
});
|
||||
|
||||
let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
|
||||
let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
|
||||
let prims: FxHashSet<PrimitiveType> =
|
||||
local_crate.primitives(cx.tcx).iter().map(|p| p.1).collect();
|
||||
|
||||
let crate_items = {
|
||||
let mut coll = ItemCollector::new();
|
||||
|
|
|
|||
|
|
@ -54,23 +54,35 @@ compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topb
|
|||
|
||||
// Now checking the background color of the sidebar.
|
||||
show-text: true
|
||||
local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
|
||||
reload:
|
||||
|
||||
// Open the sidebar menu.
|
||||
click: ".sidebar-menu-toggle"
|
||||
assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)", "color": "rgb(221, 221, 221)"})
|
||||
define-function: (
|
||||
"check-colors",
|
||||
(theme, color, background),
|
||||
[
|
||||
("local-storage", {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}),
|
||||
("reload"),
|
||||
|
||||
local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"}
|
||||
reload:
|
||||
// Open the sidebar menu.
|
||||
("click", ".sidebar-menu-toggle"),
|
||||
("assert-css", (".sidebar", {
|
||||
"background-color": |background|,
|
||||
"color": |color|,
|
||||
})),
|
||||
],
|
||||
)
|
||||
|
||||
// Open the sidebar menu.
|
||||
click: ".sidebar-menu-toggle"
|
||||
assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)", "color": "rgb(197, 197, 197)"})
|
||||
|
||||
local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"}
|
||||
reload:
|
||||
|
||||
// Open the sidebar menu.
|
||||
click: ".sidebar-menu-toggle"
|
||||
assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)", "color": "rgb(0, 0, 0)"})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "ayu",
|
||||
"color": "rgb(197, 197, 197)",
|
||||
"background": "rgb(20, 25, 31)",
|
||||
})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "dark",
|
||||
"color": "rgb(221, 221, 221)",
|
||||
"background": "rgb(80, 80, 80)",
|
||||
})
|
||||
call-function: ("check-colors", {
|
||||
"theme": "light",
|
||||
"color": "rgb(0, 0, 0)",
|
||||
"background": "rgb(245, 245, 245)",
|
||||
})
|
||||
|
|
|
|||
15
src/test/rustdoc/deref-to-primitive.rs
Normal file
15
src/test/rustdoc/deref-to-primitive.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#![crate_name = "foo"]
|
||||
|
||||
// @has 'foo/struct.Foo.html'
|
||||
// @has - '//*[@id="deref-methods-i32"]' 'Methods from Deref<Target = i32>'
|
||||
// @has - '//*[@id="deref-methods-i32-1"]//*[@id="associatedconstant.BITS"]/h4' \
|
||||
// 'pub const BITS: u32 = 32u32'
|
||||
pub struct Foo(i32);
|
||||
|
||||
impl std::ops::Deref for Foo {
|
||||
type Target = i32;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
|
@ -296,6 +296,13 @@ needed.
|
|||
|
||||
### Exporting changes to the rustc repo
|
||||
|
||||
Keep in mind that pushing is the most complicated job that josh has to do --
|
||||
pulling just filters the rustc history, but pushing needs to construct a new
|
||||
rustc history that would filter to the given Miri history! To avoid problems, it
|
||||
is a good idea to always pull immediately before you push. In particular, you
|
||||
should never do two josh pushes without an intermediate pull; that can lead to
|
||||
duplicated commits.
|
||||
|
||||
Josh needs to be running, as described above. We will use the josh proxy to push
|
||||
to your fork of rustc. Run the following in the Miri repo, assuming we are on an
|
||||
up-to-date master branch:
|
||||
|
|
|
|||
|
|
@ -281,9 +281,10 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
|
|||
eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display());
|
||||
}
|
||||
info.store(&filename);
|
||||
// For Windows, do the same thing again with `.exe` appended to the filename.
|
||||
// For Windows and WASM, do the same thing again with `.exe`/`.wasm` appended to the filename.
|
||||
// (Need to do this here as cargo moves that "binary" to a different place before running it.)
|
||||
info.store(&out_filename("", ".exe"));
|
||||
info.store(&out_filename("", ".wasm"));
|
||||
};
|
||||
|
||||
let runnable_crate = !info_query && is_runnable_crate();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
set -x
|
||||
|
||||
function begingroup {
|
||||
echo "::group::$@"
|
||||
set -x
|
||||
}
|
||||
|
||||
function endgroup {
|
||||
set +x
|
||||
echo "::endgroup"
|
||||
}
|
||||
|
||||
begingroup "Building Miri"
|
||||
|
||||
# Determine configuration for installed build
|
||||
echo "Installing release version of Miri"
|
||||
|
|
@ -14,14 +25,15 @@ export CARGO_EXTRA_FLAGS="--locked"
|
|||
./miri check --no-default-features # make sure this can be built
|
||||
./miri check --all-features # and this, too
|
||||
./miri build --all-targets # the build that all the `./miri test` below will use
|
||||
echo
|
||||
|
||||
endgroup
|
||||
|
||||
# Test
|
||||
function run_tests {
|
||||
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
|
||||
echo "Testing foreign architecture $MIRI_TEST_TARGET"
|
||||
begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
|
||||
else
|
||||
echo "Testing host architecture"
|
||||
begingroup "Testing host architecture"
|
||||
fi
|
||||
|
||||
## ui test suite
|
||||
|
|
@ -52,7 +64,6 @@ function run_tests {
|
|||
echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml
|
||||
# Run the actual test
|
||||
${PYTHON} test-cargo-miri/run-test.py
|
||||
echo
|
||||
# Clean up
|
||||
unset RUSTC MIRI
|
||||
rm -rf .cargo
|
||||
|
|
@ -63,16 +74,23 @@ function run_tests {
|
|||
cargo miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml
|
||||
done
|
||||
fi
|
||||
|
||||
endgroup
|
||||
}
|
||||
|
||||
function run_tests_minimal {
|
||||
if [ -n "${MIRI_TEST_TARGET+exists}" ]; then
|
||||
echo "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
|
||||
begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
|
||||
else
|
||||
echo "Testing MINIMAL host architecture: only testing $@"
|
||||
begingroup "Testing MINIMAL host architecture: only testing $@"
|
||||
fi
|
||||
|
||||
./miri test -- "$@"
|
||||
|
||||
# Ensure that a small smoke test of cargo-miri works.
|
||||
cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml --target ${MIRI_TEST_TARGET-$HOST_TARGET}
|
||||
|
||||
endgroup
|
||||
}
|
||||
|
||||
# host
|
||||
|
|
@ -85,6 +103,7 @@ case $HOST_TARGET in
|
|||
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
|
||||
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
|
||||
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
|
||||
MIRI_TEST_TARGET=wasm32-wasi MIRI_NO_STD=1 run_tests_minimal no_std # supports std but miri doesn't support it
|
||||
MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
|
||||
;;
|
||||
x86_64-apple-darwin)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
7477c1f4f7d6bef037d523099b240d22aa1b63a0
|
||||
454784afba5bf35b5ff14ada0e31265ad1d75e73
|
||||
|
|
|
|||
|
|
@ -838,18 +838,18 @@ impl VClockAlloc {
|
|||
&self,
|
||||
alloc_id: AllocId,
|
||||
range: AllocRange,
|
||||
global: &GlobalState,
|
||||
thread_mgr: &ThreadManager<'_, '_>,
|
||||
machine: &MiriMachine<'_, '_>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let global = machine.data_race.as_ref().unwrap();
|
||||
if global.race_detecting() {
|
||||
let (index, clocks) = global.current_thread_state(thread_mgr);
|
||||
let (index, clocks) = global.current_thread_state(&machine.threads);
|
||||
let mut alloc_ranges = self.alloc_ranges.borrow_mut();
|
||||
for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) {
|
||||
if let Err(DataRace) = range.read_race_detect(&clocks, index) {
|
||||
// Report data-race.
|
||||
return Self::report_data_race(
|
||||
global,
|
||||
thread_mgr,
|
||||
&machine.threads,
|
||||
range,
|
||||
"Read",
|
||||
false,
|
||||
|
|
@ -869,17 +869,17 @@ impl VClockAlloc {
|
|||
alloc_id: AllocId,
|
||||
range: AllocRange,
|
||||
write_type: WriteType,
|
||||
global: &mut GlobalState,
|
||||
thread_mgr: &ThreadManager<'_, '_>,
|
||||
machine: &mut MiriMachine<'_, '_>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let global = machine.data_race.as_mut().unwrap();
|
||||
if global.race_detecting() {
|
||||
let (index, clocks) = global.current_thread_state(thread_mgr);
|
||||
let (index, clocks) = global.current_thread_state(&machine.threads);
|
||||
for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) {
|
||||
if let Err(DataRace) = range.write_race_detect(&clocks, index, write_type) {
|
||||
// Report data-race
|
||||
return Self::report_data_race(
|
||||
global,
|
||||
thread_mgr,
|
||||
&machine.threads,
|
||||
range,
|
||||
write_type.get_descriptor(),
|
||||
false,
|
||||
|
|
@ -901,10 +901,9 @@ impl VClockAlloc {
|
|||
&mut self,
|
||||
alloc_id: AllocId,
|
||||
range: AllocRange,
|
||||
global: &mut GlobalState,
|
||||
thread_mgr: &ThreadManager<'_, '_>,
|
||||
machine: &mut MiriMachine<'_, '_>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.unique_access(alloc_id, range, WriteType::Write, global, thread_mgr)
|
||||
self.unique_access(alloc_id, range, WriteType::Write, machine)
|
||||
}
|
||||
|
||||
/// Detect data-races for an unsynchronized deallocate operation, will not perform
|
||||
|
|
@ -915,10 +914,9 @@ impl VClockAlloc {
|
|||
&mut self,
|
||||
alloc_id: AllocId,
|
||||
range: AllocRange,
|
||||
global: &mut GlobalState,
|
||||
thread_mgr: &ThreadManager<'_, '_>,
|
||||
machine: &mut MiriMachine<'_, '_>,
|
||||
) -> InterpResult<'tcx> {
|
||||
self.unique_access(alloc_id, range, WriteType::Deallocate, global, thread_mgr)
|
||||
self.unique_access(alloc_id, range, WriteType::Deallocate, machine)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,13 @@ pub struct Thread<'mir, 'tcx> {
|
|||
/// The virtual call stack.
|
||||
stack: Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>>,
|
||||
|
||||
/// The index of the topmost user-relevant frame in `stack`. This field must contain
|
||||
/// the value produced by `get_top_user_relevant_frame`.
|
||||
/// The `None` state here represents
|
||||
/// This field is a cache to reduce how often we call that method. The cache is manually
|
||||
/// maintained inside `MiriMachine::after_stack_push` and `MiriMachine::after_stack_pop`.
|
||||
top_user_relevant_frame: Option<usize>,
|
||||
|
||||
/// The join status.
|
||||
join_status: ThreadJoinStatus,
|
||||
|
||||
|
|
@ -147,6 +154,40 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
|
|||
fn thread_name(&self) -> &[u8] {
|
||||
if let Some(ref thread_name) = self.thread_name { thread_name } else { b"<unnamed>" }
|
||||
}
|
||||
|
||||
/// Return the top user-relevant frame, if there is one.
|
||||
/// Note that the choice to return `None` here when there is no user-relevant frame is part of
|
||||
/// justifying the optimization that only pushes of user-relevant frames require updating the
|
||||
/// `top_user_relevant_frame` field.
|
||||
fn compute_top_user_relevant_frame(&self) -> Option<usize> {
|
||||
self.stack
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find_map(|(idx, frame)| if frame.extra.is_user_relevant { Some(idx) } else { None })
|
||||
}
|
||||
|
||||
/// Re-compute the top user-relevant frame from scratch.
|
||||
pub fn recompute_top_user_relevant_frame(&mut self) {
|
||||
self.top_user_relevant_frame = self.compute_top_user_relevant_frame();
|
||||
}
|
||||
|
||||
/// Set the top user-relevant frame to the given value. Must be equal to what
|
||||
/// `get_top_user_relevant_frame` would return!
|
||||
pub fn set_top_user_relevant_frame(&mut self, frame_idx: usize) {
|
||||
debug_assert_eq!(Some(frame_idx), self.compute_top_user_relevant_frame());
|
||||
self.top_user_relevant_frame = Some(frame_idx);
|
||||
}
|
||||
|
||||
/// Returns the topmost frame that is considered user-relevant, or the
|
||||
/// top of the stack if there is no such frame, or `None` if the stack is empty.
|
||||
pub fn top_user_relevant_frame(&self) -> Option<usize> {
|
||||
debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame());
|
||||
// This can be called upon creation of an allocation. We create allocations while setting up
|
||||
// parts of the Rust runtime when we do not have any stack frames yet, so we need to handle
|
||||
// empty stacks.
|
||||
self.top_user_relevant_frame.or_else(|| self.stack.len().checked_sub(1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> {
|
||||
|
|
@ -167,6 +208,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
|
|||
state: ThreadState::Enabled,
|
||||
thread_name: None,
|
||||
stack: Vec::new(),
|
||||
top_user_relevant_frame: None,
|
||||
join_status: ThreadJoinStatus::Joinable,
|
||||
panic_payload: None,
|
||||
last_error: None,
|
||||
|
|
@ -184,8 +226,15 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
|
|||
|
||||
impl VisitTags for Thread<'_, '_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let Thread { panic_payload, last_error, stack, state: _, thread_name: _, join_status: _ } =
|
||||
self;
|
||||
let Thread {
|
||||
panic_payload,
|
||||
last_error,
|
||||
stack,
|
||||
top_user_relevant_frame: _,
|
||||
state: _,
|
||||
thread_name: _,
|
||||
join_status: _,
|
||||
} = self;
|
||||
|
||||
panic_payload.visit_tags(visit);
|
||||
last_error.visit_tags(visit);
|
||||
|
|
@ -414,7 +463,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
/// Get a shared borrow of the currently active thread.
|
||||
fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
|
||||
pub fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
|
||||
&self.threads[self.active_thread]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use std::thread;
|
|||
use log::info;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
|
|
@ -195,7 +196,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||
MiriMachine::late_init(&mut ecx, config)?;
|
||||
|
||||
// Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
|
||||
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"]);
|
||||
let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
|
||||
if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
|
||||
tcx.sess.fatal(
|
||||
"the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ pub mod convert;
|
|||
|
||||
use std::cmp;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::time::Duration;
|
||||
|
||||
use log::trace;
|
||||
|
||||
use rustc_hir::def::{DefKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -74,40 +74,67 @@ const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
|
|||
};
|
||||
|
||||
/// Gets an instance for a path.
|
||||
fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
|
||||
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then(
|
||||
|krate| {
|
||||
let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX };
|
||||
let mut items = tcx.module_children(krate);
|
||||
let mut path_it = path.iter().skip(1).peekable();
|
||||
///
|
||||
/// A `None` namespace indicates we are looking for a module.
|
||||
fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) -> Option<DefId> {
|
||||
/// Yield all children of the given item, that have the given name.
|
||||
fn find_children<'tcx: 'a, 'a>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: DefId,
|
||||
name: &'a str,
|
||||
) -> impl Iterator<Item = DefId> + 'a {
|
||||
tcx.module_children(item)
|
||||
.iter()
|
||||
.filter(move |item| item.ident.name.as_str() == name)
|
||||
.map(move |item| item.res.def_id())
|
||||
}
|
||||
|
||||
while let Some(segment) = path_it.next() {
|
||||
for item in mem::take(&mut items).iter() {
|
||||
if item.ident.name.as_str() == *segment {
|
||||
if path_it.peek().is_none() {
|
||||
return Some(item.res.def_id());
|
||||
}
|
||||
// Take apart the path: leading crate, a sequence of modules, and potentially a final item.
|
||||
let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
|
||||
let (modules, item) = if let Some(namespace) = namespace {
|
||||
let (&item_name, modules) =
|
||||
path.split_last().expect("non-module paths must have at least 2 segments");
|
||||
(modules, Some((item_name, namespace)))
|
||||
} else {
|
||||
(path, None)
|
||||
};
|
||||
|
||||
items = tcx.module_children(item.res.def_id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
},
|
||||
)
|
||||
// First find the crate.
|
||||
let krate =
|
||||
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == crate_name)?;
|
||||
let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX };
|
||||
// Then go over the modules.
|
||||
for &segment in modules {
|
||||
cur_item = find_children(tcx, cur_item, segment)
|
||||
.find(|item| tcx.def_kind(item) == DefKind::Mod)?;
|
||||
}
|
||||
// Finally, look up the desired item in this module, if any.
|
||||
match item {
|
||||
Some((item_name, namespace)) =>
|
||||
Some(
|
||||
find_children(tcx, cur_item, item_name)
|
||||
.find(|item| tcx.def_kind(item).ns() == Some(namespace))?,
|
||||
),
|
||||
None => Some(cur_item),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
/// Checks if the given crate/module exists.
|
||||
fn have_module(&self, path: &[&str]) -> bool {
|
||||
try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
|
||||
}
|
||||
|
||||
/// Gets an instance for a path; fails gracefully if the path does not exist.
|
||||
fn try_resolve_path(&self, path: &[&str]) -> Option<ty::Instance<'tcx>> {
|
||||
let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)?;
|
||||
Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did))
|
||||
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
|
||||
let tcx = self.eval_context_ref().tcx.tcx;
|
||||
let did = try_resolve_did(tcx, path, Some(namespace))?;
|
||||
Some(ty::Instance::mono(tcx, did))
|
||||
}
|
||||
|
||||
/// Gets an instance for a path.
|
||||
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
|
||||
self.try_resolve_path(path)
|
||||
fn resolve_path(&self, path: &[&str], namespace: Namespace) -> ty::Instance<'tcx> {
|
||||
self.try_resolve_path(path, namespace)
|
||||
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +142,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
/// if the path could be resolved, and None otherwise
|
||||
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_ref();
|
||||
let instance = this.resolve_path(path);
|
||||
let instance = this.resolve_path(path, Namespace::ValueNS);
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
// We don't give a span -- this isn't actually used directly by the program anyway.
|
||||
let const_val = this.eval_global(cid, None)?;
|
||||
|
|
@ -147,7 +174,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
/// Helper function to get the `TyAndLayout` of a `libc` type
|
||||
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||
let this = self.eval_context_ref();
|
||||
let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
let ty = this
|
||||
.resolve_path(&["libc", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty)
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||
let this = self.eval_context_ref();
|
||||
let ty = this
|
||||
.resolve_path(&["std", "sys", "windows", "c", name])
|
||||
.resolve_path(&["std", "sys", "windows", "c", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty)
|
||||
}
|
||||
|
|
@ -936,31 +965,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> {
|
||||
CurrentSpan { current_frame_idx: None, machine: self }
|
||||
}
|
||||
}
|
||||
|
||||
/// A `CurrentSpan` should be created infrequently (ideally once) per interpreter step. It does
|
||||
/// nothing on creation, but when `CurrentSpan::get` is called, searches the current stack for the
|
||||
/// topmost frame which corresponds to a local crate, and returns the current span in that frame.
|
||||
/// The result of that search is cached so that later calls are approximately free.
|
||||
#[derive(Clone)]
|
||||
pub struct CurrentSpan<'a, 'mir, 'tcx> {
|
||||
current_frame_idx: Option<usize>,
|
||||
machine: &'a MiriMachine<'mir, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
|
||||
pub fn machine(&self) -> &'a MiriMachine<'mir, 'tcx> {
|
||||
self.machine
|
||||
}
|
||||
|
||||
/// Get the current span, skipping non-local frames.
|
||||
/// Get the current span in the topmost function which is workspace-local and not
|
||||
/// `#[track_caller]`.
|
||||
/// This function is backed by a cache, and can be assumed to be very fast.
|
||||
pub fn get(&mut self) -> Span {
|
||||
let idx = self.current_frame_idx();
|
||||
self.stack().get(idx).map(Frame::current_span).unwrap_or(rustc_span::DUMMY_SP)
|
||||
/// It will work even when the stack is empty.
|
||||
pub fn current_span(&self) -> Span {
|
||||
self.top_user_relevant_frame()
|
||||
.map(|frame_idx| self.stack()[frame_idx].current_span())
|
||||
.unwrap_or(rustc_span::DUMMY_SP)
|
||||
}
|
||||
|
||||
/// Returns the span of the *caller* of the current operation, again
|
||||
|
|
@ -968,46 +980,27 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
|
|||
/// current operation is not in a local crate.
|
||||
/// This is useful when we are processing something which occurs on function-entry and we want
|
||||
/// to point at the call to the function, not the function definition generally.
|
||||
pub fn get_caller(&mut self) -> Span {
|
||||
pub fn caller_span(&self) -> Span {
|
||||
// We need to go down at least to the caller (len - 2), or however
|
||||
// far we have to go to find a frame in a local crate.
|
||||
let local_frame_idx = self.current_frame_idx();
|
||||
let stack = self.stack();
|
||||
let idx = cmp::min(local_frame_idx, stack.len().saturating_sub(2));
|
||||
stack.get(idx).map(Frame::current_span).unwrap_or(rustc_span::DUMMY_SP)
|
||||
// far we have to go to find a frame in a local crate which is also not #[track_caller].
|
||||
let frame_idx = self.top_user_relevant_frame().unwrap();
|
||||
let frame_idx = cmp::min(frame_idx, self.stack().len().checked_sub(2).unwrap());
|
||||
self.stack()[frame_idx].current_span()
|
||||
}
|
||||
|
||||
fn stack(&self) -> &[Frame<'mir, 'tcx, Provenance, machine::FrameData<'tcx>>] {
|
||||
self.machine.threads.active_thread_stack()
|
||||
self.threads.active_thread_stack()
|
||||
}
|
||||
|
||||
fn current_frame_idx(&mut self) -> usize {
|
||||
*self
|
||||
.current_frame_idx
|
||||
.get_or_insert_with(|| Self::compute_current_frame_index(self.machine))
|
||||
fn top_user_relevant_frame(&self) -> Option<usize> {
|
||||
self.threads.active_thread_ref().top_user_relevant_frame()
|
||||
}
|
||||
|
||||
// Find the position of the inner-most frame which is part of the crate being
|
||||
// compiled/executed, part of the Cargo workspace, and is also not #[track_caller].
|
||||
#[inline(never)]
|
||||
fn compute_current_frame_index(machine: &MiriMachine<'_, '_>) -> usize {
|
||||
machine
|
||||
.threads
|
||||
.active_thread_stack()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find_map(|(idx, frame)| {
|
||||
let def_id = frame.instance.def_id();
|
||||
if (def_id.is_local() || machine.local_crates.contains(&def_id.krate))
|
||||
&& !frame.instance.def.requires_caller_location(machine.tcx)
|
||||
{
|
||||
Some(idx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(0)
|
||||
/// This is the source of truth for the `is_user_relevant` flag in our `FrameExtra`.
|
||||
pub fn is_user_relevant(&self, frame: &Frame<'mir, 'tcx, Provenance>) -> bool {
|
||||
let def_id = frame.instance.def_id();
|
||||
(def_id.is_local() || self.local_crates.contains(&def_id.krate))
|
||||
&& !frame.instance.def.requires_caller_location(self.tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ pub use crate::diagnostics::{
|
|||
pub use crate::eval::{
|
||||
create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith,
|
||||
};
|
||||
pub use crate::helpers::{CurrentSpan, EvalContextExt as _};
|
||||
pub use crate::helpers::EvalContextExt as _;
|
||||
pub use crate::intptrcast::ProvenanceMode;
|
||||
pub use crate::machine::{
|
||||
AllocExtra, FrameData, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
|
||||
|
|
|
|||
|
|
@ -50,12 +50,18 @@ pub struct FrameData<'tcx> {
|
|||
/// for the start of this frame. When we finish executing this frame,
|
||||
/// we use this to register a completed event with `measureme`.
|
||||
pub timing: Option<measureme::DetachedTiming>,
|
||||
|
||||
/// Indicates whether a `Frame` is part of a workspace-local crate and is also not
|
||||
/// `#[track_caller]`. We compute this once on creation and store the result, as an
|
||||
/// optimization.
|
||||
/// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span`
|
||||
pub is_user_relevant: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Omitting `timing`, it does not support `Debug`.
|
||||
let FrameData { stacked_borrows, catch_unwind, timing: _ } = self;
|
||||
let FrameData { stacked_borrows, catch_unwind, timing: _, is_user_relevant: _ } = self;
|
||||
f.debug_struct("FrameData")
|
||||
.field("stacked_borrows", stacked_borrows)
|
||||
.field("catch_unwind", catch_unwind)
|
||||
|
|
@ -65,7 +71,7 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
|
|||
|
||||
impl VisitTags for FrameData<'_> {
|
||||
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
|
||||
let FrameData { catch_unwind, stacked_borrows, timing: _ } = self;
|
||||
let FrameData { catch_unwind, stacked_borrows, timing: _, is_user_relevant: _ } = self;
|
||||
|
||||
catch_unwind.visit_tags(visit);
|
||||
stacked_borrows.visit_tags(visit);
|
||||
|
|
@ -895,13 +901,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
|
||||
let alloc = alloc.into_owned();
|
||||
let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| {
|
||||
Stacks::new_allocation(
|
||||
id,
|
||||
alloc.size(),
|
||||
stacked_borrows,
|
||||
kind,
|
||||
ecx.machine.current_span(),
|
||||
)
|
||||
Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind, &ecx.machine)
|
||||
});
|
||||
let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| {
|
||||
data_race::AllocExtra::new_allocation(
|
||||
|
|
@ -1003,22 +1003,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
range: AllocRange,
|
||||
) -> InterpResult<'tcx> {
|
||||
if let Some(data_race) = &alloc_extra.data_race {
|
||||
data_race.read(
|
||||
alloc_id,
|
||||
range,
|
||||
machine.data_race.as_ref().unwrap(),
|
||||
&machine.threads,
|
||||
)?;
|
||||
data_race.read(alloc_id, range, machine)?;
|
||||
}
|
||||
if let Some(stacked_borrows) = &alloc_extra.stacked_borrows {
|
||||
stacked_borrows.borrow_mut().before_memory_read(
|
||||
alloc_id,
|
||||
prov_extra,
|
||||
range,
|
||||
machine.stacked_borrows.as_ref().unwrap(),
|
||||
machine.current_span(),
|
||||
&machine.threads,
|
||||
)?;
|
||||
stacked_borrows
|
||||
.borrow_mut()
|
||||
.before_memory_read(alloc_id, prov_extra, range, machine)?;
|
||||
}
|
||||
if let Some(weak_memory) = &alloc_extra.weak_memory {
|
||||
weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
|
||||
|
|
@ -1035,22 +1025,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
range: AllocRange,
|
||||
) -> InterpResult<'tcx> {
|
||||
if let Some(data_race) = &mut alloc_extra.data_race {
|
||||
data_race.write(
|
||||
alloc_id,
|
||||
range,
|
||||
machine.data_race.as_mut().unwrap(),
|
||||
&machine.threads,
|
||||
)?;
|
||||
data_race.write(alloc_id, range, machine)?;
|
||||
}
|
||||
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
|
||||
stacked_borrows.get_mut().before_memory_write(
|
||||
alloc_id,
|
||||
prov_extra,
|
||||
range,
|
||||
machine.stacked_borrows.as_ref().unwrap(),
|
||||
machine.current_span(),
|
||||
&machine.threads,
|
||||
)?;
|
||||
stacked_borrows.get_mut().before_memory_write(alloc_id, prov_extra, range, machine)?;
|
||||
}
|
||||
if let Some(weak_memory) = &alloc_extra.weak_memory {
|
||||
weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap());
|
||||
|
|
@ -1070,21 +1048,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
|
||||
}
|
||||
if let Some(data_race) = &mut alloc_extra.data_race {
|
||||
data_race.deallocate(
|
||||
alloc_id,
|
||||
range,
|
||||
machine.data_race.as_mut().unwrap(),
|
||||
&machine.threads,
|
||||
)?;
|
||||
data_race.deallocate(alloc_id, range, machine)?;
|
||||
}
|
||||
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
|
||||
stacked_borrows.get_mut().before_memory_deallocation(
|
||||
alloc_id,
|
||||
prove_extra,
|
||||
range,
|
||||
machine.stacked_borrows.as_ref().unwrap(),
|
||||
machine.current_span(),
|
||||
&machine.threads,
|
||||
machine,
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
@ -1126,7 +1097,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame(&ecx.machine)),
|
||||
catch_unwind: None,
|
||||
timing,
|
||||
is_user_relevant: ecx.machine.is_user_relevant(&frame),
|
||||
};
|
||||
|
||||
Ok(frame.with_extra(extra))
|
||||
}
|
||||
|
||||
|
|
@ -1174,6 +1147,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
|
||||
#[inline(always)]
|
||||
fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
|
||||
if ecx.frame().extra.is_user_relevant {
|
||||
// We just pushed a local frame, so we know that the topmost local frame is the topmost
|
||||
// frame. If we push a non-local frame, there's no need to do anything.
|
||||
let stack_len = ecx.active_thread_stack().len();
|
||||
ecx.active_thread_mut().set_top_user_relevant_frame(stack_len - 1);
|
||||
}
|
||||
|
||||
if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) }
|
||||
}
|
||||
|
||||
|
|
@ -1183,6 +1163,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
mut frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>,
|
||||
unwinding: bool,
|
||||
) -> InterpResult<'tcx, StackPopJump> {
|
||||
if frame.extra.is_user_relevant {
|
||||
// All that we store is whether or not the frame we just removed is local, so now we
|
||||
// have no idea where the next topmost local frame is. So we recompute it.
|
||||
// (If this ever becomes a bottleneck, we could have `push` store the previous
|
||||
// user-relevant frame and restore that here.)
|
||||
ecx.active_thread_mut().recompute_top_user_relevant_frame();
|
||||
}
|
||||
let timing = frame.extra.timing.take();
|
||||
if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
|
||||
stacked_borrows.borrow_mut().end_call(&frame.extra);
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ pub enum PathConversion {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
|
||||
pub fn os_str_to_bytes<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, &[u8]> {
|
||||
Ok(os_str.as_bytes())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
|
||||
pub fn os_str_to_bytes<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, &[u8]> {
|
||||
// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the
|
||||
// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually
|
||||
// valid.
|
||||
|
|
@ -34,11 +34,11 @@ pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> {
|
||||
pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> {
|
||||
Ok(OsStr::from_bytes(bytes))
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> {
|
||||
pub fn bytes_to_os_str<'tcx>(bytes: &[u8]) -> InterpResult<'tcx, &OsStr> {
|
||||
let s = std::str::from_utf8(bytes)
|
||||
.map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?;
|
||||
Ok(OsStr::new(s))
|
||||
|
|
|
|||
|
|
@ -261,6 +261,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// (that would be basically https://github.com/rust-lang/miri/issues/450),
|
||||
// we specifically look up the static in libstd that we know is placed
|
||||
// in that section.
|
||||
if !this.have_module(&["std"]) {
|
||||
// Looks like we are running in a `no_std` crate.
|
||||
// That also means no TLS dtors callback to call.
|
||||
return Ok(());
|
||||
}
|
||||
let thread_callback =
|
||||
this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?;
|
||||
let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?;
|
||||
|
|
|
|||
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