[[package]]
name = "compiletest_rs"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a"
+checksum = "d7d8975604ebad8b6660796802377eb6495045c5606168fc1b8d19a4dd9bfa46"
dependencies = [
"diff",
"filetime",
"arena",
"either",
"graphviz",
+ "itertools 0.8.0",
"log",
"log_settings",
"polonius-engine",
"log",
"rustc_data_structures",
"rustc_index",
+ "rustc_macros",
"serialize",
"syntax_pos",
]
"rustc_errors",
"rustc_index",
"rustc_lexer",
+ "rustc_macros",
"scoped-tls",
"serialize",
"smallvec 1.0.0",
[[package]]
name = "tester"
-version = "0.5.1"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd0d1044cb5ca390e9c93f8c35abd2c55484397dfd786f189321aa34605ee6ab"
+checksum = "7647e6d732eb84375d8e7abda37818f81861ddbfc7235e33f4983cb254b71e4f"
dependencies = [
"getopts",
"libc",
/// By changing `impl PartialEq for Book` to `impl PartialEq<BookFormat> for Book`,
/// we allow `BookFormat`s to be compared with `Book`s.
///
-/// You can also combine these implementations to let the `==` operator work with
-/// two different types:
-///
-/// ```
+/// A comparison like the one above, which ignores some fields of the struct,
+/// can be dangerous. It can easily lead to an unintended violation of the
+/// requirements for a partial equivalence relation. For example, if we kept
+/// the above implementation of `PartialEq<Book>` for `BookFormat` and added an
+/// implementation of `PartialEq<Book>` for `Book` (either via a `#[derive]` or
+/// via the manual implementation from the first example) then the result would
+/// violate transitivity:
+///
+/// ```should_panic
/// #[derive(PartialEq)]
/// enum BookFormat {
/// Paperback,
/// Ebook,
/// }
///
+/// #[derive(PartialEq)]
/// struct Book {
/// isbn: i32,
/// format: BookFormat,
/// }
/// }
///
-/// impl PartialEq for Book {
-/// fn eq(&self, other: &Book) -> bool {
-/// self.isbn == other.isbn
-/// }
-/// }
+/// fn main() {
+/// let b1 = Book { isbn: 1, format: BookFormat::Paperback };
+/// let b2 = Book { isbn: 2, format: BookFormat::Paperback };
///
-/// let b1 = Book { isbn: 3, format: BookFormat::Paperback };
-/// let b2 = Book { isbn: 3, format: BookFormat::Ebook };
+/// assert!(b1 == BookFormat::Paperback);
+/// assert!(BookFormat::Paperback == b2);
///
-/// assert!(b1 == BookFormat::Paperback);
-/// assert!(BookFormat::Ebook != b1);
-/// assert!(b1 == b2);
+/// // The following should hold by transitivity but doesn't.
+/// assert!(b1 == b2); // <-- PANICS
+/// }
/// ```
///
/// # Examples
Fuse::new(self)
}
- /// Do something with each element of an iterator, passing the value on.
+ /// Does something with each element of an iterator, passing the value on.
///
/// When using iterators, you'll often chain several of them together.
/// While working on such code, you might want to check out what's
(left, right)
}
- /// Reorder the elements of this iterator *in-place* according to the given predicate,
+ /// Reorders the elements of this iterator *in-place* according to the given predicate,
/// such that all those that return `true` precede all those that return `false`.
/// Returns the number of `true` elements found.
///
/// Bindings like `A: Debug` are represented as a special type `A =
/// $::Debug` that is understood by the astconv code.
///
-/// FIXME(alexreg) -- why have a separate type for the binding case,
-/// wouldn't it be better to make the `ty` field an enum like:
+/// FIXME(alexreg): why have a separate type for the binding case,
+/// wouldn't it be better to make the `ty` field an enum like the
+/// following?
///
/// ```
/// enum TypeBindingKind {
Err,
}
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable, PartialEq)]
pub struct InlineAsmOutput {
pub constraint: Symbol,
pub is_rw: bool,
// NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
// it needs to be `Clone` and use plain `Vec<T>` instead of `HirVec<T>`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable, PartialEq)]
pub struct InlineAsmInner {
pub asm: Symbol,
pub asm_str_style: StrStyle,
}
}
-impl_stable_hash_for!(enum ast::CrateSugar {
- JustCrate,
- PubCrate,
-});
-
impl<'a> HashStable<StableHashingContext<'a>> for hir::VisibilityKind {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
+++ /dev/null
-//! This module contains `HashStable` implementations for various data types
-//! that don't fit into any of the other impls_xxx modules.
-
-impl_stable_hash_for!(enum ::rustc_target::spec::PanicStrategy {
- Abort,
- Unwind
-});
use syntax::feature_gate;
use syntax::token;
use syntax::tokenstream;
-use syntax_pos::symbol::SymbolStr;
use syntax_pos::SourceFile;
use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX};
use smallvec::SmallVec;
-use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher};
-
-impl<'a> HashStable<StableHashingContext<'a>> for SymbolStr {
- #[inline]
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let str = self as &str;
- str.hash_stable(hcx, hasher)
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for SymbolStr {
- type KeyType = SymbolStr;
-
- #[inline]
- fn to_stable_hash_key(&self,
- _: &StableHashingContext<'a>)
- -> SymbolStr {
- self.clone()
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for ast::Name {
- #[inline]
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- self.as_str().hash_stable(hcx, hasher);
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::Name {
- type KeyType = SymbolStr;
-
- #[inline]
- fn to_stable_hash_key(&self,
- _: &StableHashingContext<'a>)
- -> SymbolStr {
- self.as_str()
- }
-}
-
-impl_stable_hash_for!(enum ::syntax::ast::AsmDialect {
- Att,
- Intel
-});
-
-impl_stable_hash_for!(enum ::syntax_pos::hygiene::MacroKind {
- Bang,
- Attr,
- Derive,
-});
-
-
-impl_stable_hash_for!(enum ::rustc_target::spec::abi::Abi {
- Cdecl,
- Stdcall,
- Fastcall,
- Vectorcall,
- Thiscall,
- Aapcs,
- Win64,
- SysV64,
- PtxKernel,
- Msp430Interrupt,
- X86Interrupt,
- AmdGpuKernel,
- EfiApi,
- Rust,
- C,
- System,
- RustIntrinsic,
- RustCall,
- PlatformIntrinsic,
- Unadjusted
-});
-
-impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
-impl_stable_hash_for!(struct ::syntax::attr::Stability {
- level,
- feature,
- rustc_depr,
- promotable,
- allow_const_fn_ptr,
- const_stability
-});
-
-impl_stable_hash_for!(enum ::syntax::edition::Edition {
- Edition2015,
- Edition2018,
-});
-
-impl<'a> HashStable<StableHashingContext<'a>>
-for ::syntax::attr::StabilityLevel {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- mem::discriminant(self).hash_stable(hcx, hasher);
- match *self {
- ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue, ref is_soft } => {
- reason.hash_stable(hcx, hasher);
- issue.hash_stable(hcx, hasher);
- is_soft.hash_stable(hcx, hasher);
- }
- ::syntax::attr::StabilityLevel::Stable { ref since } => {
- since.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
-impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason, suggestion });
-
-impl_stable_hash_for!(enum ::syntax::attr::IntType {
- SignedInt(int_ty),
- UnsignedInt(uint_ty)
-});
-
-impl_stable_hash_for!(enum ::syntax::ast::LitIntType {
- Signed(int_ty),
- Unsigned(int_ty),
- Unsuffixed
-});
-
-impl_stable_hash_for!(enum ::syntax::ast::LitFloatType {
- Suffixed(float_ty),
- Unsuffixed
-});
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
impl_stable_hash_for!(struct ::syntax::ast::Lit {
kind,
span
});
-impl_stable_hash_for!(enum ::syntax::ast::LitKind {
- Str(value, style),
- ByteStr(value),
- Byte(value),
- Char(value),
- Int(value, lit_int_type),
- Float(value, lit_float_type),
- Bool(value),
- Err(value)
-});
-
impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
-impl_stable_hash_for!(enum ::syntax::ast::IntTy { Isize, I8, I16, I32, I64, I128 });
-impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, U8, U16, U32, U64, U128 });
-impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 });
-impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal });
-impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst });
-impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final });
impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, ident });
-impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) });
-impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner });
-impl_stable_hash_for!(enum ::syntax::ast::Movability { Static, Movable });
-impl_stable_hash_for!(enum ::syntax::ast::CaptureBy { Value, Ref });
-impl_stable_hash_for!(enum ::syntax::ast::IsAuto { Yes, No });
-impl_stable_hash_for!(enum ::syntax::ast::ImplPolarity { Positive, Negative });
impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
}
}
-impl_stable_hash_for!(enum token::LitKind {
- Bool,
- Byte,
- Char,
- Integer,
- Float,
- Str,
- ByteStr,
- StrRaw(n),
- ByteStrRaw(n),
- Err
-});
-
-impl_stable_hash_for!(struct token::Lit {
- kind,
- symbol,
- suffix
-});
-
impl<'a> HashStable<StableHashingContext<'a>> for token::TokenKind {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
NameValue(lit)
});
-impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency {
- Transparent,
- SemiTransparent,
- Opaque,
-});
-
impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData {
kind,
parent -> _,
edition
});
-impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind {
- Root,
- Macro(kind, descr),
- AstPass(kind),
- Desugaring(kind)
-});
-
-impl_stable_hash_for!(enum ::syntax_pos::hygiene::AstPass {
- StdImports,
- TestHarness,
- ProcMacroHarness,
- PluginMacroDefs,
-});
-
-impl_stable_hash_for!(enum ::syntax_pos::hygiene::DesugaringKind {
- CondTemporary,
- Async,
- Await,
- QuestionMark,
- OpaqueTy,
- ForLoop,
- TryBlock
-});
-
-impl_stable_hash_for!(enum ::syntax_pos::FileName {
- Real(pb),
- Macros(s),
- QuoteExpansion(s),
- Anon(s),
- MacroExpansion(s),
- ProcMacroSourceCode(s),
- CliCrateAttr(s),
- CfgSpec(s),
- Custom(s),
- DocTest(pb, line),
-});
-
impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let SourceFile {
}
}
-impl_stable_hash_for!(enum ::syntax::ast::Mutability {
- Immutable,
- Mutable
-});
-
impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope {
type KeyType = region::Scope;
mod hcx;
mod impls_hir;
-mod impls_misc;
mod impls_ty;
mod impls_syntax;
match *r {
ty::ReLateBound(index, ..) => {
if index >= self.binder_index {
- bug!("escaping late bound region during canonicalization")
+ bug!("escaping late-bound region during canonicalization");
} else {
r
}
.canonicalize_free_region(self, r),
ty::ReClosureBound(..) => {
- bug!("closure bound region encountered during canonicalization")
+ bug!("closure bound region encountered during canonicalization");
}
}
}
ty::Infer(ty::TyVar(vid)) => {
debug!("canonical: type var found with vid {:?}", vid);
match self.infcx.unwrap().probe_ty_var(vid) {
- // `t` could be a float / int variable: canonicalize that instead
+ // `t` could be a float / int variable; canonicalize that instead.
Ok(t) => {
debug!("(resolved to {:?})", t);
self.fold_ty(t)
}
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
- // result
+ // result.
Err(mut ui) => {
if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
// FIXME: perf problem described in #55921.
use super::lexical_region_resolve::RegionResolutionError;
use super::region_constraints::GenericKind;
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
-use crate::infer::{self, SuppressRegionErrors};
use crate::hir;
use crate::hir::def_id::DefId;
use crate::hir::Node;
+use crate::infer::{self, SuppressRegionErrors};
use crate::infer::opaque_types;
use crate::middle::region;
-use crate::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
-use crate::traits::{ObligationCauseCode};
+use crate::traits::{
+ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+};
use crate::ty::error::TypeError;
use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable};
+
use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
-use std::{cmp, fmt};
+use rustc_error_codes::*;
use syntax_pos::{Pos, Span};
-use rustc_error_codes::*;
+use std::{cmp, fmt};
mod note;
}
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
- /// suggest it.
+ /// suggests it.
fn suggest_as_ref_where_appropriate(
&self,
span: Span,
}
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
-/// obligation into a series of `'a: 'b` constraints and "verifys", as
+/// obligation into a series of `'a: 'b` constraints and "verify"s, as
/// described on the module comment. The final constraints are emitted
/// via a "delegate" of type `D` -- this is usually the `infcx`, which
/// accrues them into the `region_obligations` code, but for NLL we
}
}
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
pub enum PanicInfo<O> {
Panic {
msg: Symbol,
-use std::fmt::{self, Display};
-use std::convert::TryFrom;
+use super::{AllocId, InterpResult};
use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
+
use rustc_macros::HashStable;
-use super::{AllocId, InterpResult};
+use std::convert::TryFrom;
+use std::fmt::{self, Display};
/// Used by `check_in_alloc` to indicate context of check
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
// FIXME: is it possible to over/underflow here?
if i < 0 {
- // Trickery to ensure that i64::min_value() works fine: compute n = -i.
- // This formula only works for true negative values, it overflows for zero!
+ // Trickery to ensure that `i64::min_value()` works fine: compute `n = -i`.
+ // This formula only works for true negative values; it overflows for zero!
let n = u64::max_value() - (i as u64) + 1;
let res = val.overflowing_sub(n);
self.truncate_to_ptr(res)
///
/// Defaults to the index based and loosely coupled `AllocId`.
///
-/// Pointer is also generic over the `Tag` associated with each pointer,
+/// `Pointer` is also generic over the `Tag` associated with each pointer,
/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd,
RustcEncodable, RustcDecodable, Hash, HashStable)]
}
}
-/// Produces a `Pointer` which points to the beginning of the `Allocation`.
+/// Produces a `Pointer` that points to the beginning of the `Allocation`.
impl From<AllocId> for Pointer {
#[inline(always)]
fn from(alloc_id: AllocId) -> Self {
use crate::hir::def::{CtorKind, Namespace};
use crate::hir::def_id::DefId;
use crate::hir;
-use crate::mir::interpret::{PanicInfo, Scalar};
+use crate::mir::interpret::{GlobalAlloc, PanicInfo, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
- if self.local_decls[local].is_user_variable.is_some() {
+ if self.local_decls[local].is_user_variable() {
None
} else {
Some(local)
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
- if self.local_decls[local].is_user_variable.is_some() {
+ if self.local_decls[local].is_user_variable() {
Some(local)
} else {
None
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
let decl = &self.local_decls[local];
- if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut {
+ if decl.is_user_variable() && decl.mutability == Mutability::Mut {
Some(local)
} else {
None
(1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
let decl = &self.local_decls[local];
- if (decl.is_user_variable.is_some() || index < self.arg_count + 1)
+ if (decl.is_user_variable() || index < self.arg_count + 1)
&& decl.mutability == Mutability::Mut
{
Some(local)
/// Temporaries and the return place are always mutable.
pub mutability: Mutability,
- /// `Some(binding_mode)` if this corresponds to a user-declared local variable.
- ///
- /// This is solely used for local diagnostics when generating
- /// warnings/errors when compiling the current crate, and
- /// therefore it need not be visible across crates. pnkfelix
- /// currently hypothesized we *need* to wrap this in a
- /// `ClearCrossCrate` as long as it carries as `HirId`.
- pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>,
+ // FIXME(matthewjasper) Don't store in this in `Body`
+ pub local_info: LocalInfo<'tcx>,
/// `true` if this is an internal local.
///
/// then it is a temporary created for evaluation of some
/// subexpression of some block's tail expression (with no
/// intervening statement context).
+ // FIXME(matthewjasper) Don't store in this in `Body`
pub is_block_tail: Option<BlockTailInfo>,
/// The type of this local.
/// e.g., via `let x: T`, then we carry that type here. The MIR
/// borrow checker needs this information since it can affect
/// region inference.
+ // FIXME(matthewjasper) Don't store in this in `Body`
pub user_ty: UserTypeProjections,
/// The name of the local, used in debuginfo and pretty-printing.
pub visibility_scope: SourceScope,
}
+/// Extra information about a local that's used for diagnostics.
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub enum LocalInfo<'tcx> {
+ /// A user-defined local variable or function parameter
+ ///
+ /// The `BindingForm` is solely used for local diagnostics when generating
+ /// warnings/errors when compiling the current crate, and therefore it need
+ /// not be visible across crates.
+ User(ClearCrossCrate<BindingForm<'tcx>>),
+ /// A temporary created that references the static with the given `DefId`.
+ StaticRef { def_id: DefId, is_thread_local: bool },
+ /// Any other temporary, the return place, or an anonymous function parameter.
+ Other,
+}
+
impl<'tcx> LocalDecl<'tcx> {
/// Returns `true` only if local is a binding that can itself be
/// made mutable via the addition of the `mut` keyword, namely
/// - `let x = ...`,
/// - or `match ... { C(x) => ... }`
pub fn can_be_made_mutable(&self) -> bool {
- match self.is_user_variable {
- Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+ match self.local_info {
+ LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
}))) => true,
- Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm))) => true,
+ LocalInfo::User(
+ ClearCrossCrate::Set(BindingForm::ImplicitSelf(ImplicitSelfKind::Imm)),
+ ) => true,
_ => false,
}
/// `ref mut ident` binding. (Such bindings cannot be made into
/// mutable bindings, but the inverse does not necessarily hold).
pub fn is_nonref_binding(&self) -> bool {
- match self.is_user_variable {
- Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+ match self.local_info {
+ LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
binding_mode: ty::BindingMode::BindByValue(_),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
}))) => true,
- Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
+ LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_))) => true,
_ => false,
}
}
+ /// Returns `true` if this variable is a named variable or function
+ /// parameter declared by the user.
+ #[inline]
+ pub fn is_user_variable(&self) -> bool {
+ match self.local_info {
+ LocalInfo::User(_) => true,
+ _ => false,
+ }
+ }
+
/// Returns `true` if this is a reference to a variable bound in a `match`
/// expression that is used to access said variable for the guard of the
/// match arm.
pub fn is_ref_for_guard(&self) -> bool {
- match self.is_user_variable {
- Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
+ match self.local_info {
+ LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)) => true,
+ _ => false,
+ }
+ }
+
+ /// Returns `Some` if this is a reference to a static item that is used to
+ /// access that static
+ pub fn is_ref_to_static(&self) -> bool {
+ match self.local_info {
+ LocalInfo::StaticRef { .. } => true,
+ _ => false,
+ }
+ }
+
+ /// Returns `Some` if this is a reference to a static item that is used to
+ /// access that static
+ pub fn is_ref_to_thread_local(&self) -> bool {
+ match self.local_info {
+ LocalInfo::StaticRef { is_thread_local, .. } => is_thread_local,
_ => false,
}
}
source_info: SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE },
visibility_scope: OUTERMOST_SOURCE_SCOPE,
internal,
- is_user_variable: None,
+ local_info: LocalInfo::Other,
is_block_tail: None,
}
}
internal: false,
is_block_tail: None,
name: None, // FIXME maybe we do want some name here?
- is_user_variable: None,
+ local_info: LocalInfo::Other,
}
}
}
pub kind: TerminatorKind<'tcx>,
}
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
pub enum TerminatorKind<'tcx> {
/// Block should have one successor in the graph; we jump there.
Goto { target: BasicBlock },
}
}
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub enum StatementKind<'tcx> {
/// Write the RHS Rvalue to the LHS Place.
Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
}
/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists.
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable, PartialEq)]
pub enum FakeReadCause {
/// Inject a fake read of the borrowed input at the end of each guards
/// code.
ForIndex,
}
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct InlineAsm<'tcx> {
pub asm: hir::InlineAsmInner,
pub outputs: Box<[Place<'tcx>]>,
///////////////////////////////////////////////////////////////////////////
/// Rvalues
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
pub enum Rvalue<'tcx> {
/// x (either a move or copy, depending on type of x)
Use(Operand<'tcx>),
pub literal: &'tcx ty::Const<'tcx>,
}
+impl Constant<'tcx> {
+ pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.literal.val.try_to_scalar() {
+ Some(Scalar::Ptr(ptr)) => match tcx.alloc_map.lock().get(ptr.alloc_id) {
+ Some(GlobalAlloc::Static(def_id)) => Some(def_id),
+ Some(_) => None,
+ None => {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP, "MIR cannot contain dangling const pointers",
+ );
+ None
+ },
+ },
+ _ => None,
+ }
+ }
+}
+
/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
/// * `let (x, _): T = ...` -- here, the `projs` vector would contain
/// `field[0]` (aka `.0`), indicating that the type of `s` is
/// determined by finding the type of the `.0` field from `T`.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
pub struct UserTypeProjection {
pub base: UserTypeAnnotationIndex,
pub projs: Vec<ProjectionKind>,
let ty = self.ty
.builtin_deref(true)
.unwrap_or_else(|| {
- bug!("deref projection of non-dereferencable ty {:?}", self)
+ bug!("deref projection of non-dereferenceable ty {:?}", self)
})
.ty;
PlaceTy::from_ty(ty)
source_info,
visibility_scope,
internal: _,
- is_user_variable: _,
+ local_info: _,
is_block_tail: _,
} = local_decl;
//! Contains infrastructure for configuring the compiler, including parsing
//! command-line options.
-// ignore-tidy-filelength
-
use crate::lint;
use crate::middle::cstore;
use crate::session::{early_error, early_warn, Session};
use crate::session::search_paths::SearchPath;
-use crate::hir::map as hir_map;
use rustc_data_structures::fx::FxHashSet;
// by the compiler.
json_artifact_notifications: bool [TRACKED],
- pretty: Option<(PpMode, Option<UserIdentifiedItem>)> [UNTRACKED],
+ pretty: Option<PpMode> [UNTRACKED],
}
);
force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
"force use of the frame pointers"),
debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "explicitly enable the cfg(debug_assertions) directive"),
+ "explicitly enable the `cfg(debug_assertions)` directive"),
inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
"set the threshold for inlining a function (default: 225)"),
panic: Option<PanicStrategy> = (None, parse_panic_strategy,
matches: &getopts::Matches,
debugging_opts: &DebuggingOptions,
efmt: ErrorOutputType,
-) -> Option<(PpMode, Option<UserIdentifiedItem>)> {
+) -> Option<PpMode> {
let pretty = if debugging_opts.unstable_options {
matches.opt_default("pretty", "normal").map(|a| {
// stable pretty-print variants only
efmt: ErrorOutputType,
name: &str,
extended: bool,
- ) -> (PpMode, Option<UserIdentifiedItem>) {
+ ) -> PpMode {
use PpMode::*;
use PpSourceMode::*;
- let mut split = name.splitn(2, '=');
- let first = split.next().unwrap();
- let opt_second = split.next();
- let first = match (first, extended) {
+ let first = match (name, extended) {
("normal", _) => PpmSource(PpmNormal),
("identified", _) => PpmSource(PpmIdentified),
("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
}
}
};
- let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok());
- (first, opt_second)
+ first
}
}
}
impl PpMode {
- pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool {
+ pub fn needs_ast_map(&self) -> bool {
use PpMode::*;
use PpSourceMode::*;
match *self {
PpmSource(PpmNormal) |
PpmSource(PpmEveryBodyLoops) |
- PpmSource(PpmIdentified) => opt_uii.is_some(),
+ PpmSource(PpmIdentified) => false,
PpmSource(PpmExpanded) |
PpmSource(PpmExpandedIdentified) |
}
}
-#[derive(Clone, Debug)]
-pub enum UserIdentifiedItem {
- ItemViaNode(ast::NodeId),
- ItemViaPath(Vec<String>),
-}
-
-impl FromStr for UserIdentifiedItem {
- type Err = ();
- fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
- use UserIdentifiedItem::*;
- Ok(s.parse()
- .map(ast::NodeId::from_u32)
- .map(ItemViaNode)
- .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
- }
-}
-
-pub enum NodesMatchingUII<'a> {
- NodesMatchingDirect(std::option::IntoIter<ast::NodeId>),
- NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
-}
-
-impl<'a> Iterator for NodesMatchingUII<'a> {
- type Item = ast::NodeId;
-
- fn next(&mut self) -> Option<ast::NodeId> {
- use NodesMatchingUII::*;
- match self {
- &mut NodesMatchingDirect(ref mut iter) => iter.next(),
- &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- use NodesMatchingUII::*;
- match self {
- &NodesMatchingDirect(ref iter) => iter.size_hint(),
- &NodesMatchingSuffix(ref iter) => iter.size_hint(),
- }
- }
-}
-
-impl UserIdentifiedItem {
- pub fn reconstructed_input(&self) -> String {
- use UserIdentifiedItem::*;
- match *self {
- ItemViaNode(node_id) => node_id.to_string(),
- ItemViaPath(ref parts) => parts.join("::"),
- }
- }
-
- pub fn all_matching_node_ids<'a, 'hir>(&'a self,
- map: &'a hir_map::Map<'hir>)
- -> NodesMatchingUII<'a> {
- use UserIdentifiedItem::*;
- use NodesMatchingUII::*;
- match *self {
- ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
- ItemViaPath(ref parts) => {
- NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
- }
- }
- }
-
- pub fn to_one_node_id(self,
- user_option: &str,
- sess: &Session,
- map: &hir_map::Map<'_>)
- -> ast::NodeId {
- let fail_because = |is_wrong_because| -> ast::NodeId {
- let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
- {}, which {}",
- user_option,
- self.reconstructed_input(),
- is_wrong_because);
- sess.fatal(&message)
- };
-
- let mut saw_node = ast::DUMMY_NODE_ID;
- let mut seen = 0;
- for node in self.all_matching_node_ids(map) {
- saw_node = node;
- seen += 1;
- if seen > 1 {
- fail_because("does not resolve uniquely");
- }
- }
- if seen == 0 {
- fail_because("does not resolve to any item");
- }
-
- assert!(seen == 1);
- return saw_node;
- }
-}
-
/// Command-line arguments passed to the compiler have to be incorporated with
/// the dependency tracking system for incremental compilation. This module
/// provides some utilities to make this more convenient.
use syntax::feature_gate;
use errors::json::JsonEmitter;
use syntax::source_map;
-use syntax::sess::{ParseSess, ProcessCfgMod};
+use syntax::sess::ParseSess;
use syntax_pos::{MultiSpan, Span};
use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
sopts: config::Options,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry,
- process_cfg_mod: ProcessCfgMod,
) -> Session {
let file_path_mapping = sopts.file_path_mapping();
Lrc::new(source_map::SourceMap::new(file_path_mapping)),
DiagnosticOutput::Default,
Default::default(),
- process_cfg_mod,
)
}
source_map: Lrc<source_map::SourceMap>,
diagnostics_output: DiagnosticOutput,
lint_caps: FxHashMap<lint::LintId, lint::Level>,
- process_cfg_mod: ProcessCfgMod,
) -> Session {
// FIXME: This is not general enough to make the warning lint completely override
// normal diagnostic warnings, since the warning lint can also be denied and changed
diagnostic_handler,
source_map,
lint_caps,
- process_cfg_mod,
)
}
span_diagnostic: errors::Handler,
source_map: Lrc<source_map::SourceMap>,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
- process_cfg_mod: ProcessCfgMod,
) -> Session {
let self_profiler =
if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile {
let parse_sess = ParseSess::with_span_handler(
span_diagnostic,
source_map,
- process_cfg_mod,
);
let sysroot = match &sopts.maybe_sysroot {
Some(sysroot) => sysroot.clone(),
-//! Support code for rustdoc and external tools . You really don't
-//! want to be using this unless you need to.
+//! Support code for rustdoc and external tools.
+//! You really don't want to be using this unless you need to.
use super::*;
-use std::collections::hash_map::Entry;
-use std::collections::VecDeque;
-
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-
use crate::ty::fold::TypeFolder;
use crate::ty::{Region, RegionVid};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+
+use std::collections::hash_map::Entry;
+use std::collections::VecDeque;
+
// FIXME(twk): this is obviously not nice to duplicate like that
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
pub enum RegionTarget<'tcx> {
}
impl AutoTraitFinder<'tcx> {
- // The core logic responsible for computing the bounds for our synthesized impl.
- //
- // To calculate the bounds, we call SelectionContext.select in a loop. Like FulfillmentContext,
- // we recursively select the nested obligations of predicates we encounter. However, whenever we
- // encounter an UnimplementedError involving a type parameter, we add it to our ParamEnv. Since
- // our goal is to determine when a particular type implements an auto trait, Unimplemented
- // errors tell us what conditions need to be met.
- //
- // This method ends up working somewhat similarly to FulfillmentContext, but with a few key
- // differences. FulfillmentContext works under the assumption that it's dealing with concrete
- // user code. According, it considers all possible ways that a Predicate could be met - which
- // isn't always what we want for a synthesized impl. For example, given the predicate 'T:
- // Iterator', FulfillmentContext can end up reporting an Unimplemented error for T:
- // IntoIterator - since there's an implementation of Iteratpr where T: IntoIterator,
- // FulfillmentContext will drive SelectionContext to consider that impl before giving up. If we
- // were to rely on FulfillmentContext's decision, we might end up synthesizing an impl like
- // this:
- // 'impl<T> Send for Foo<T> where T: IntoIterator'
- //
- // While it might be technically true that Foo implements Send where T: IntoIterator,
- // the bound is overly restrictive - it's really only necessary that T: Iterator.
- //
- // For this reason, evaluate_predicates handles predicates with type variables specially. When
- // we encounter an Unimplemented error for a bound such as 'T: Iterator', we immediately add it
- // to our ParamEnv, and add it to our stack for recursive evaluation. When we later select it,
- // we'll pick up any nested bounds, without ever inferring that 'T: IntoIterator' needs to
- // hold.
- //
- // One additional consideration is supertrait bounds. Normally, a ParamEnv is only ever
- // constructed once for a given type. As part of the construction process, the ParamEnv will
- // have any supertrait bounds normalized - e.g., if we have a type 'struct Foo<T: Copy>', the
- // ParamEnv will contain 'T: Copy' and 'T: Clone', since 'Copy: Clone'. When we construct our
- // own ParamEnv, we need to do this ourselves, through traits::elaborate_predicates, or else
- // SelectionContext will choke on the missing predicates. However, this should never show up in
- // the final synthesized generics: we don't want our generated docs page to contain something
- // like 'T: Copy + Clone', as that's redundant. Therefore, we keep track of a separate
- // 'user_env', which only holds the predicates that will actually be displayed to the user.
+ /// The core logic responsible for computing the bounds for our synthesized impl.
+ ///
+ /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like
+ /// `FulfillmentContext`, we recursively select the nested obligations of predicates we
+ /// encounter. However, whenever we encounter an `UnimplementedError` involving a type
+ /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular
+ /// type implements an auto trait, Unimplemented errors tell us what conditions need to be met.
+ ///
+ /// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key
+ /// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete
+ /// user code. According, it considers all possible ways that a `Predicate` could be met, which
+ /// isn't always what we want for a synthesized impl. For example, given the predicate `T:
+ /// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T:
+ /// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`,
+ /// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up.
+ /// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl
+ /// like this:
+ ///
+ /// impl<T> Send for Foo<T> where T: IntoIterator
+ ///
+ /// While it might be technically true that Foo implements Send where `T: IntoIterator`,
+ /// the bound is overly restrictive - it's really only necessary that `T: Iterator`.
+ ///
+ /// For this reason, `evaluate_predicates` handles predicates with type variables specially.
+ /// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately
+ /// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later
+ /// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator`
+ /// needs to hold.
+ ///
+ /// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever
+ /// constructed once for a given type. As part of the construction process, the `ParamEnv` will
+ /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the
+ /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our
+ /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or
+ /// else `SelectionContext` will choke on the missing predicates. However, this should never
+ /// show up in the final synthesized generics: we don't want our generated docs page to contain
+ /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a
+ /// separate `user_env`, which only holds the predicates that will actually be displayed to the
+ /// user.
fn evaluate_predicates(
&self,
infcx: &InferCtxt<'_, 'tcx>,
continue;
}
- // Call infcx.resolve_vars_if_possible to see if we can
+ // Call `infcx.resolve_vars_if_possible` to see if we can
// get rid of any inference variables.
let obligation = infcx.resolve_vars_if_possible(
&Obligation::new(dummy_cause.clone(), new_env, pred)
match &result {
&Ok(Some(ref vtable)) => {
- // If we see an explicit negative impl (e.g., 'impl !Send for MyStruct'),
+ // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`),
// we immediately bail out, since it's impossible for us to continue.
match vtable {
Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => {
- // Blame tidy for the weird bracket placement
+ // Blame 'tidy' for the weird bracket placement.
if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative
{
- debug!("evaluate_nested_obligations: Found explicit negative impl\
+ debug!("evaluate_nested_obligations: found explicit negative impl\
{:?}, bailing out", impl_def_id);
return None;
}
predicates.push_back(pred);
} else {
debug!(
- "evaluate_nested_obligations: Unimplemented found, bailing: \
+ "evaluate_nested_obligations: `Unimplemented` found, bailing: \
{:?} {:?} {:?}",
ty,
pred,
return Some((new_env, final_user_env));
}
- // This method is designed to work around the following issue:
- // When we compute auto trait bounds, we repeatedly call SelectionContext.select,
- // progressively building a ParamEnv based on the results we get.
- // However, our usage of SelectionContext differs from its normal use within the compiler,
- // in that we capture and re-reprocess predicates from Unimplemented errors.
- //
- // This can lead to a corner case when dealing with region parameters.
- // During our selection loop in evaluate_predicates, we might end up with
- // two trait predicates that differ only in their region parameters:
- // one containing a HRTB lifetime parameter, and one containing a 'normal'
- // lifetime parameter. For example:
- //
- // T as MyTrait<'a>
- // T as MyTrait<'static>
- //
- // If we put both of these predicates in our computed ParamEnv, we'll
- // confuse SelectionContext, since it will (correctly) view both as being applicable.
- //
- // To solve this, we pick the 'more strict' lifetime bound - i.e., the HRTB
- // Our end goal is to generate a user-visible description of the conditions
- // under which a type implements an auto trait. A trait predicate involving
- // a HRTB means that the type needs to work with any choice of lifetime,
- // not just one specific lifetime (e.g., 'static).
+ /// This method is designed to work around the following issue:
+ /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`,
+ /// progressively building a `ParamEnv` based on the results we get.
+ /// However, our usage of `SelectionContext` differs from its normal use within the compiler,
+ /// in that we capture and re-reprocess predicates from `Unimplemented` errors.
+ ///
+ /// This can lead to a corner case when dealing with region parameters.
+ /// During our selection loop in `evaluate_predicates`, we might end up with
+ /// two trait predicates that differ only in their region parameters:
+ /// one containing a HRTB lifetime parameter, and one containing a 'normal'
+ /// lifetime parameter. For example:
+ ///
+ /// T as MyTrait<'a>
+ /// T as MyTrait<'static>
+ ///
+ /// If we put both of these predicates in our computed `ParamEnv`, we'll
+ /// confuse `SelectionContext`, since it will (correctly) view both as being applicable.
+ ///
+ /// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB
+ /// Our end goal is to generate a user-visible description of the conditions
+ /// under which a type implements an auto trait. A trait predicate involving
+ /// a HRTB means that the type needs to work with any choice of lifetime,
+ /// not just one specific lifetime (e.g., `'static`).
fn add_user_pred<'c>(
&self,
user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
if !new_substs.types().eq(old_substs.types()) {
// We can't compare lifetimes if the types are different,
- // so skip checking old_pred
+ // so skip checking `old_pred`.
return true;
}
new_substs.regions().zip(old_substs.regions())
{
match (new_region, old_region) {
- // If both predicates have an 'ReLateBound' (a HRTB) in the
- // same spot, we do nothing
+ // If both predicates have an `ReLateBound` (a HRTB) in the
+ // same spot, we do nothing.
(
ty::RegionKind::ReLateBound(_, _),
ty::RegionKind::ReLateBound(_, _),
// varaible).
//
// In both cases, we want to remove the old predicate,
- // from user_computed_preds, and replace it with the new
+ // from `user_computed_preds`, and replace it with the new
// one. Having both the old and the new
- // predicate in a ParamEnv would confuse SelectionContext
+ // predicate in a `ParamEnv` would confuse `SelectionContext`.
//
// We're currently in the predicate passed to 'retain',
- // so we return 'false' to remove the old predicate from
- // user_computed_preds
+ // so we return `false` to remove the old predicate from
+ // `user_computed_preds`.
return false;
}
(_, ty::RegionKind::ReLateBound(_, _)) |
// predicate has some other type of region.
//
// We want to leave the old
- // predicate in user_computed_preds, and skip adding
- // new_pred to user_computed_params.
+ // predicate in `user_computed_preds`, and skip adding
+ // new_pred to `user_computed_params`.
should_add_new = false
},
_ => {}
}
}
- // This is very similar to handle_lifetimes. However, instead of matching ty::Region's
- // to each other, we match ty::RegionVid's to ty::Region's
+ /// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s
+ /// to each other, we match `ty::RegionVid`s to `ty::Region`s.
fn map_vid_to_region<'cx>(
&self,
regions: &RegionConstraintData<'cx>,
finished_map.insert(v1, r1);
}
(&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
- // Do nothing - we don't care about regions that are smaller than vids
+ // Do nothing; we don't care about regions that are smaller than vids.
}
(&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
if let Entry::Occupied(v) = vid_map.entry(*smaller) {
/// Obligation incurred due to a coercion.
Coercion { source: Ty<'tcx>, target: Ty<'tcx> },
- // Various cases where expressions must be sized/copy/etc:
- /// L = X implies that L is Sized
+ /// Various cases where expressions must be `Sized` / `Copy` / etc.
+ /// `L = X` implies that `L` is `Sized`.
AssignmentLhsSized,
- /// (x1, .., xn) must be Sized
+ /// `(x1, .., xn)` must be `Sized`.
TupleInitializerSized,
- /// S { ... } must be Sized
+ /// `S { ... }` must be `Sized`.
StructInitializerSized,
- /// Type of each variable must be Sized
+ /// Type of each variable must be `Sized`.
VariableType(hir::HirId),
- /// Argument type must be Sized
+ /// Argument type must be `Sized`.
SizedArgumentType,
- /// Return type must be Sized
+ /// Return type must be `Sized`.
SizedReturnType,
- /// Yield type must be Sized
+ /// Yield type must be `Sized`.
SizedYieldType,
- /// [T,..n] --> T must be Copy. If `true`, suggest `const_in_array_repeat_expressions` feature
- /// flag.
+ /// `[T, ..n]` implies that `T` must be `Copy`.
+ /// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
RepeatVec(bool),
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
/// Constant expressions must be sized.
ConstSized,
- /// Static items must have `Sync` type
+ /// `static` items must have `Sync` type.
SharedStatic,
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
/// the impl's type parameters.
///
/// The type parameter `N` indicates the type used for "nested
-/// obligations" that are required by the impl. During type check, this
+/// obligations" that are required by the impl. During type-check, this
/// is `Obligation`, as one might expect. During codegen, however, this
/// is `()`, because codegen only requires a shallow resolution of an
/// impl, and nested obligations are satisfied later.
return None;
}
- // the method may have some early-bound lifetimes, add
- // regions for those
+ // The method may have some early-bound lifetimes; add regions for those.
let substs = trait_ref.map_bound(|trait_ref|
InternalSubsts::for_item(tcx, def_id, |param, _|
match param.kind {
)
);
- // the trait type may have higher-ranked lifetimes in it;
- // so erase them if they appear, so that we get the type
- // at some particular call site
+ // The trait type may have higher-ranked lifetimes in it;
+ // erase them if they appear, so that we get the type
+ // at some particular call site.
let substs = tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&substs
);
- // It's possible that the method relies on where clauses that
+ // It's possible that the method relies on where-clauses that
// do not hold for this particular set of type parameters.
// Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435).
struct TraitObligationStack<'prev, 'tcx> {
obligation: &'prev TraitObligation<'tcx>,
- /// Trait ref from `obligation` but "freshened" with the
+ /// The trait ref from `obligation` but "freshened" with the
/// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
previous: TraitObligationStackList<'prev, 'tcx>,
- /// Number of parent frames plus one -- so the topmost frame has depth 1.
+ /// The number of parent frames plus one (thus, the topmost frame has depth 1).
depth: usize,
- /// Depth-first number of this node in the search graph -- a
- /// pre-order index. Basically a freshly incremented counter.
+ /// The depth-first number of this node in the search graph -- a
+ /// pre-order index. Basically, a freshly incremented counter.
dfn: usize,
}
/// }
/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
///
-/// we can't just use the impl to resolve the <T as AsDebug> obligation
-/// - a type from another crate (that doesn't implement fmt::Debug) could
-/// implement AsDebug.
+/// we can't just use the impl to resolve the `<T as AsDebug>` obligation
+/// -- a type from another crate (that doesn't implement `fmt::Debug`) could
+/// implement `AsDebug`.
///
/// Because where-clauses match the type exactly, multiple clauses can
/// only match if there are unresolved variables, and we can mostly just
/// }
/// fn main() { foo(false); }
///
-/// Here the obligation <T as Foo<$0>> can be matched by both the blanket
-/// impl and the where-clause. We select the where-clause and unify $0=bool,
+/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
+/// impl and the where-clause. We select the where-clause and unify `$0=bool`,
/// so the program prints "false". However, if the where-clause is omitted,
-/// the blanket impl is selected, we unify $0=(), and the program prints
+/// the blanket impl is selected, we unify `$0=()`, and the program prints
/// "()".
///
/// Exactly the same issues apply to projection and object candidates, except
/// parameter environment.
#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)]
enum SelectionCandidate<'tcx> {
- /// If has_nested is false, there are no *further* obligations
BuiltinCandidate {
+ /// `false` if there are no *further* obligations.
has_nested: bool,
},
ParamCandidate(ty::PolyTraitRef<'tcx>),
GeneratorCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous
- /// types generated for a fn pointer type (e.g., `fn(int)->int`)
+ /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate,
TraitAliasCandidate(DefId),
}
struct SelectionCandidateSet<'tcx> {
- // a list of candidates that definitely apply to the current
+ // A list of candidates that definitely apply to the current
// obligation (meaning: types unify).
vec: Vec<SelectionCandidate<'tcx>>,
- // if this is true, then there were candidates that might or might
+ // If `true`, then there were candidates that might or might
// not have applied, but we couldn't tell. This occurs when some
// of the input types are type variables, in which case there are
// various "builtin" rules that might or might not trigger.
/// When does the builtin impl for `T: Trait` apply?
enum BuiltinImplConditions<'tcx> {
- /// The impl is conditional on T1,T2,.. : Trait
+ /// The impl is conditional on `T1, T2, ...: Trait`.
Where(ty::Binder<Vec<Ty<'tcx>>>),
/// There is no built-in impl. There may be some other
/// candidate (a where-clause or user-defined impl).
/// the categories it's easy to see that the unions are correct.
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
pub enum EvaluationResult {
- /// Evaluation successful
+ /// Evaluation successful.
EvaluatedToOk,
- /// Evaluation successful, but there were unevaluated region obligations
+ /// Evaluation successful, but there were unevaluated region obligations.
EvaluatedToOkModuloRegions,
- /// Evaluation is known to be ambiguous - it *might* hold for some
+ /// Evaluation is known to be ambiguous -- it *might* hold for some
/// assignment of inference variables, but it might not.
///
- /// While this has the same meaning as `EvaluatedToUnknown` - we can't
- /// know whether this obligation holds or not - it is the result we
+ /// While this has the same meaning as `EvaluatedToUnknown` -- we can't
+ /// know whether this obligation holds or not -- it is the result we
/// would get with an empty stack, and therefore is cacheable.
EvaluatedToAmbig,
/// Evaluation failed because of recursion involving inference
/// We know this branch can't be a part of a minimal proof-tree for
/// the "root" of our cycle, because then we could cut out the recursion
/// and maintain a valid proof tree. However, this does not mean
- /// that all the obligations on this branch do not hold - it's possible
+ /// that all the obligations on this branch do not hold -- it's possible
/// that we entered this branch "speculatively", and that there
/// might be some other way to prove this obligation that does not
- /// go through this cycle - so we can't cache this as a failure.
+ /// go through this cycle -- so we can't cache this as a failure.
///
/// For example, suppose we have this:
///
/// ```rust,ignore (pseudo-Rust)
- /// pub trait Trait { fn xyz(); }
- /// // This impl is "useless", but we can still have
- /// // an `impl Trait for SomeUnsizedType` somewhere.
- /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
+ /// pub trait Trait { fn xyz(); }
+ /// // This impl is "useless", but we can still have
+ /// // an `impl Trait for SomeUnsizedType` somewhere.
+ /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
///
- /// pub fn foo<T: Trait + ?Sized>() {
- /// <T as Trait>::xyz();
- /// }
+ /// pub fn foo<T: Trait + ?Sized>() {
+ /// <T as Trait>::xyz();
+ /// }
/// ```
///
/// When checking `foo`, we have to prove `T: Trait`. This basically
/// translates into this:
///
/// ```plain,ignore
- /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
+ /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
/// ```
///
/// When we try to prove it, we first go the first option, which
// 1. If no applicable impl or parameter bound can be found.
// 2. If the output type parameters in the obligation do not match
// those specified by the impl/bound. For example, if the obligation
- // is `Vec<Foo>:Iterable<Bar>`, but the impl specifies
+ // is `Vec<Foo>: Iterable<Bar>`, but the impl specifies
// `impl<T> Iterable<T> for Vec<T>`, than an error would result.
/// Attempts to satisfy the obligation. If successful, this will affect the surrounding
debug!("evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})",
previous_stack.head(), obligation);
- // Previous_stack stores a TraitObligatiom, while 'obligation' is
- // a PredicateObligation. These are distinct types, so we can't
- // use any Option combinator method that would force them to be
- // the same
+ // `previous_stack` stores a `TraitObligatiom`, while `obligation` is
+ // a `PredicateObligation`. These are distinct types, so we can't
+ // use any `Option` combinator method that would force them to be
+ // the same.
match previous_stack.head() {
Some(h) => self.check_recursion_limit(&obligation, h.obligation)?,
None => self.check_recursion_limit(&obligation, &obligation)?
}
ty::Predicate::Subtype(ref p) => {
- // does this code ever run?
+ // Does this code ever run?
match self.infcx
.subtype_predicate(&obligation.cause, obligation.param_env, p)
{
},
ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
- // we do not consider region relationships when
- // evaluating trait matches
+ // We do not consider region relationships when evaluating trait matches.
Ok(EvaluatedToOkModuloRegions)
}
stack: &TraitObligationStack<'_, 'tcx>,
) -> Option<EvaluationResult> {
if let Some(cycle_depth) = stack.iter()
- .skip(1) // skip top-most frame
+ .skip(1) // Skip top-most frame.
.find(|prev| stack.obligation.param_env == prev.obligation.param_env &&
stack.fresh_trait_ref == prev.fresh_trait_ref)
.map(|stack| stack.depth)
.skip_binder()
.input_types()
.any(|ty| ty.is_fresh());
- // this check was an imperfect workaround for a bug n the old
- // intercrate mode, it should be removed when that goes away.
+ // This check was an imperfect workaround for a bug in the old
+ // intercrate mode; it should be removed when that goes away.
if unbound_input_types && self.intercrate == Some(IntercrateMode::Issue43355) {
debug!(
"evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
}
/// For defaulted traits, we use a co-inductive strategy to solve, so
- /// that recursion is ok. This routine returns true if the top of the
+ /// that recursion is ok. This routine returns `true` if the top of the
/// stack (`cycle[0]`):
///
/// - is a defaulted trait,
result
}
- /// Further evaluate `candidate` to decide whether all type parameters match and whether nested
+ /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
/// obligations are met. Returns whether `candidate` remains viable after this further
/// scrutiny.
fn evaluate_candidate<'o>(
.insert(trait_ref, WithDepNode::new(dep_node, result));
}
- // For various reasons, it's possible for a subobligation
- // to have a *lower* recursion_depth than the obligation used to create it.
- // Projection sub-obligations may be returned from the projection cache,
- // which results in obligations with an 'old' recursion_depth.
- // Additionally, methods like ty::wf::obligations and
- // InferCtxt.subtype_predicate produce subobligations without
- // taking in a 'parent' depth, causing the generated subobligations
- // to have a recursion_depth of 0
- //
- // To ensure that obligation_depth never decreasees, we force all subobligations
- // to have at least the depth of the original obligation.
+ /// For various reasons, it's possible for a subobligation
+ /// to have a *lower* recursion_depth than the obligation used to create it.
+ /// Projection sub-obligations may be returned from the projection cache,
+ /// which results in obligations with an 'old' `recursion_depth`.
+ /// Additionally, methods like `ty::wf::obligations` and
+ /// `InferCtxt.subtype_predicate` produce subobligations without
+ /// taking in a 'parent' depth, causing the generated subobligations
+ /// to have a `recursion_depth` of `0`.
+ ///
+ /// To ensure that obligation_depth never decreasees, we force all subobligations
+ /// to have at least the depth of the original obligation.
fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(&self, it: I,
min_depth: usize) {
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
}
- // Check that the recursion limit has not been exceeded.
- //
- // The weird return type of this function allows it to be used with the 'try' (?)
- // operator within certain functions
+ /// Checks that the recursion limit has not been exceeded.
+ ///
+ /// The weird return type of this function allows it to be used with the `try` (`?`)
+ /// operator within certain functions.
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
&self,
obligation: &Obligation<'tcx, T>,
// not update) the cache.
self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
-
// Check the cache. Note that we freshen the trait-ref
// separately rather than using `stack.fresh_trait_ref` --
// this is because we want the unbound variables to be
// candidate set is *individually* applicable. Now we have to
// figure out if they contain mutual incompatibilities. This
// frequently arises if we have an unconstrained input type --
- // for example, we are looking for $0:Eq where $0 is some
+ // for example, we are looking for `$0: Eq` where `$0` is some
// unconstrained type variable. In that case, we'll get a
- // candidate which assumes $0 == int, one that assumes $0 ==
- // usize, etc. This spells an ambiguity.
+ // candidate which assumes $0 == int, one that assumes `$0 ==
+ // usize`, etc. This spells an ambiguity.
// If there is more than one candidate, first winnow them down
// by considering extra conditions (nested obligations and so
// and we were to see some code `foo.push_clone()` where `boo`
// is a `Vec<Bar>` and `Bar` does not implement `Clone`. If
// we were to winnow, we'd wind up with zero candidates.
- // Instead, we select the right impl now but report `Bar does
- // not implement Clone`.
+ // Instead, we select the right impl now but report "`Bar` does
+ // not implement `Clone`".
if candidates.len() == 1 {
return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
}
// avoid us having to fear that coherence results "pollute"
// the master cache. Since coherence executes pretty quickly,
// it's not worth going to more trouble to increase the
- // hit-rate I don't think.
+ // hit-rate, I don't think.
if self.intercrate.is_some() {
return false;
}
}
/// Determines whether can we safely cache the result
- /// of selecting an obligation. This is almost always 'true',
- /// except when dealing with certain ParamCandidates.
+ /// of selecting an obligation. This is almost always `true`,
+ /// except when dealing with certain `ParamCandidate`s.
///
- /// Ordinarily, a ParamCandidate will contain no inference variables,
- /// since it was usually produced directly from a DefId. However,
+ /// Ordinarily, a `ParamCandidate` will contain no inference variables,
+ /// since it was usually produced directly from a `DefId`. However,
/// certain cases (currently only librustdoc's blanket impl finder),
- /// a ParamEnv may be explicitly constructed with inference types.
+ /// a `ParamEnv` may be explicitly constructed with inference types.
/// When this is the case, we do *not* want to cache the resulting selection
/// candidate. This is due to the fact that it might not always be possible
/// to equate the obligation's trait ref and the candidate's trait ref,
///
/// Because of this, we always want to re-run the full selection
/// process for our obligation the next time we see it, since
- /// we might end up picking a different SelectionCandidate (or none at all)
+ /// we might end up picking a different `SelectionCandidate` (or none at all).
fn can_cache_candidate(&self,
result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>
) -> bool {
if self.can_use_global_caches(param_env) {
if let Err(Overflow) = candidate {
- // Don't cache overflow globally; we only produce this
- // in certain modes.
+ // Don't cache overflow globally; we only produce this in certain modes.
} else if !trait_ref.has_local_value() {
if !candidate.has_local_value() {
debug!(
"insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
trait_ref, candidate,
);
- // This may overwrite the cache with the same value
+ // This may overwrite the cache with the same value.
tcx.selection_cache
.hashmap
.borrow_mut()
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
- // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
+ // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
// types have builtin support for `Clone`.
let clone_conditions = self.copy_clone_conditions(obligation);
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
) {
debug!("assemble_candidates_for_projected_tys({:?})", obligation);
- // before we go into the whole placeholder thing, just
+ // Before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().kind {
ty::Projection(_) | ty::Opaque(..) => {}
self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
}
- /// Given an obligation like `<SomeTrait for T>`, search the obligations that the caller
+ /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
/// supplied to find out whether it is listed among them.
///
- /// Never affects inference environment.
+ /// Never affects the inference environment.
fn assemble_candidates_from_caller_bounds<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
Ok(())
}
- /// Implement one of the `Fn()` family for a fn pointer.
+ /// Implements one of the `Fn()` family for a fn pointer.
fn assemble_fn_pointer_candidates(
&mut self,
obligation: &TraitObligation<'tcx>,
return Ok(());
}
- // Okay to skip binder because what we are inspecting doesn't involve bound regions
+ // Okay to skip binder because what we are inspecting doesn't involve bound regions.
let self_ty = *obligation.self_ty().skip_binder();
match self_ty.kind {
ty::Infer(ty::TyVar(_)) => {
debug!("assemble_fn_pointer_candidates: ambiguous self-type");
- candidates.ambiguous = true; // could wind up being a fn() type
+ candidates.ambiguous = true; // Could wind up being a fn() type.
}
- // provide an impl, but only for suitable `fn` pointers
+ // Provide an impl, but only for suitable `fn` pointers.
ty::FnDef(..) | ty::FnPtr(_) => {
if let ty::FnSig {
unsafety: hir::Unsafety::Normal,
Ok(())
}
- /// Search for impls that might apply to `obligation`.
+ /// Searches for impls that might apply to `obligation`.
fn assemble_candidates_from_impls(
&mut self,
obligation: &TraitObligation<'tcx>,
// this path.
}
ty::Infer(ty::TyVar(_)) => {
- // the auto impl might apply, we don't know
+ // The auto impl might apply; we don't know.
candidates.ambiguous = true;
}
ty::Generator(_, _, movability)
Ok(())
}
- /// Search for impls that might apply to `obligation`.
+ /// Searches for impls that might apply to `obligation`.
fn assemble_candidates_from_object_ty(
&mut self,
obligation: &TraitObligation<'tcx>,
return;
}
} else {
- // Only auto-trait bounds exist.
+ // Only auto trait bounds exist.
return;
}
}
// we are looking for. Specifically, do not only check for the
// correct trait, but also the correct type parameters.
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
- // but `Foo` is declared as `trait Foo : Bar<u32>`.
+ // but `Foo` is declared as `trait Foo: Bar<u32>`.
let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
.filter(|upcast_trait_ref| {
self.infcx.probe(|_| {
})
}
- /// Search for unsizing that might apply to `obligation`.
+ /// Searches for unsizing that might apply to `obligation`.
fn assemble_candidates_for_unsizing(
&mut self,
obligation: &TraitObligation<'tcx>,
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
// Upcasts permit two things:
//
- // 1. Dropping builtin bounds, e.g., `Foo+Send` to `Foo`
- // 2. Tightening the region bound, e.g., `Foo+'a` to `Foo+'b` if `'a : 'b`
+ // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
+ // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
//
// Note that neither of these changes requires any
- // change at runtime. Eventually this will be
+ // change at runtime. Eventually this will be
// generalized.
//
// We always upcast when we can because of reason
.all(|b| data_a.auto_traits().any(|a| a == b))
}
- // T -> Trait.
+ // `T` -> `Trait`
(_, &ty::Dynamic(..)) => true,
- // Ambiguous handling is below T -> Trait, because inference
- // variables can still implement Unsize<Trait> and nested
+ // Ambiguous handling is below `T` -> `Trait`, because inference
+ // variables can still implement `Unsize<Trait>` and nested
// obligations will have the final say (likely deferred).
(&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
debug!("assemble_candidates_for_unsizing: ambiguous");
false
}
- // [T; n] -> [T].
+ // `[T; n]` -> `[T]`
(&ty::Array(..), &ty::Slice(_)) => true,
- // Struct<T> -> Struct<U>.
+ // `Struct<T>` -> `Struct<U>`
(&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
def_id_a == def_id_b
}
- // (.., T) -> (.., U).
+ // `(.., T)` -> `(.., U)`
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
_ => false,
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
match other.candidate {
- // Prefer BuiltinCandidate { has_nested: false } to anything else.
+ // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
BuiltinCandidate { has_nested: false } => true,
when there are other valid candidates"
);
}
- // Prefer BuiltinCandidate { has_nested: false } to anything else.
+ // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
BuiltinCandidate { has_nested: false } => false,
when there are other valid candidates"
);
}
- // Prefer BuiltinCandidate { has_nested: false } to anything else.
+ // Prefer `BuiltinCandidate { has_nested: false }` to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
BuiltinCandidate { has_nested: false } => false,
ImplCandidate(other_def) => {
// See if we can toss out `victim` based on specialization.
// This requires us to know *for sure* that the `other` impl applies
- // i.e., EvaluatedToOk:
+ // i.e., `EvaluatedToOk`.
if other.evaluation.must_apply_modulo_regions() {
match victim.candidate {
ImplCandidate(victim_def) => {
match victim.candidate {
ParamCandidate(ref cand) => {
// Prefer these to a global where-clause bound
- // (see issue #50825)
+ // (see issue #50825).
is_global(cand) && other.evaluation.must_apply_modulo_regions()
}
_ => false,
types.skip_binder().to_vec()
}
- // for `PhantomData<T>`, we pass `T`
+ // For `PhantomData<T>`, we pass `T`.
ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(),
ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(),
}
BuiltinObjectCandidate => {
- // This indicates something like `(Trait+Send) :
- // Send`. In this case, we know that this holds
- // because that's what the object type is telling us,
- // and there's really no additional obligations to
- // prove and no types in particular to unify etc.
+ // This indicates something like `Trait + Send: Send`. In this case, we know that
+ // this holds because that's what the object type is telling us, and there's really
+ // no additional obligations to prove and no types in particular to unify, etc.
Ok(VtableParam(Vec::new()))
}
// We want to find the first supertrait in the list of
// supertraits that we can unify with, and do that
// unification. We know that there is exactly one in the list
- // where we can unify because otherwise select would have
+ // where we can unify, because otherwise select would have
// reported an ambiguity. (When we do find a match, also
// record it for later.)
let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(
},
);
- // Additionally, for each of the nonmatching predicates that
+ // Additionally, for each of the non-matching predicates that
// we pass over, we sum up the set of number of vtable
// entries, so that we can compute the offset for the selected
// trait.
trait_ref,
)?);
- // FIXME: chalk
+ // FIXME: Chalk
if !self.tcx().sess.opts.debugging_opts.chalk {
obligations.push(Obligation::new(
) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx();
- // assemble_candidates_for_unsizing should ensure there are no late bound
+ // `assemble_candidates_for_unsizing` should ensure there are no late-bound
// regions here. See the comment there for more details.
let source = self.infcx
.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
match (&source.kind, &target.kind) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
- // See assemble_candidates_for_unsizing for more info.
+ // See `assemble_candidates_for_unsizing` for more info.
let existential_predicates = data_a.map_bound(|data_a| {
let iter =
data_a.principal().map(|x| ty::ExistentialPredicate::Trait(x))
- .into_iter().chain(
- data_a
- .projection_bounds()
- .map(|x| ty::ExistentialPredicate::Projection(x)),
- )
- .chain(
- data_b
- .auto_traits()
- .map(ty::ExistentialPredicate::AutoTrait),
- );
+ .into_iter().chain(
+ data_a
+ .projection_bounds()
+ .map(|x| ty::ExistentialPredicate::Projection(x)),
+ )
+ .chain(
+ data_b
+ .auto_traits()
+ .map(ty::ExistentialPredicate::AutoTrait),
+ );
tcx.mk_existential_predicates(iter)
});
let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
//
- // FIXME: This condition is arguably too strong -- it
- // would suffice for the source trait to be a
- // *subtype* of the target trait. In particular
- // changing from something like `for<'a, 'b> Foo<'a,
- // 'b>` to `for<'a> Foo<'a, 'a>` should be
+ // FIXME: This condition is arguably too strong -- it would
+ // suffice for the source trait to be a *subtype* of the target
+ // trait. In particular, changing from something like
+ // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
// permitted. And, indeed, in the in commit
// 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
- // condition was loosened. However, when the leak check was added
- // back, using subtype here actually guies the coercion code in
- // such a way that it accepts `old-lub-glb-object.rs`. This is probably
- // a good thing, but I've modified this to `.eq` because I want
- // to continue rejecting that test (as we have done for quite some time)
- // before we are firmly comfortable with what our behavior
- // should be there. -nikomatsakis
+ // condition was loosened. However, when the leak check was
+ // added back, using subtype here actually guides the coercion
+ // code in such a way that it accepts `old-lub-glb-object.rs`.
+ // This is probably a good thing, but I've modified this to `.eq`
+ // because I want to continue rejecting that test (as we have
+ // done for quite some time) before we are firmly comfortable
+ // with what our behavior should be there. -nikomatsakis
let InferOk { obligations, .. } = self.infcx
.at(&obligation.cause, obligation.param_env)
.eq(target, source_trait) // FIXME -- see below
));
}
- // T -> Trait.
+ // `T` -> `Trait`
(_, &ty::Dynamic(ref data, r)) => {
let mut object_dids = data.auto_traits()
.chain(data.principal_def_id());
};
// Create obligations:
- // - Casting T to Trait
+ // - Casting `T` to `Trait`
// - For all the various builtin bounds attached to the object cast. (In other
- // words, if the object type is Foo+Send, this would create an obligation for the
- // Send check.)
+ // words, if the object type is `Foo + Send`, this would create an obligation for
+ // the `Send` check.)
// - Projection predicates
nested.extend(
data.iter()
- .map(|d| predicate_to_obligation(d.with_self_ty(tcx, source))),
+ .map(|predicate|
+ predicate_to_obligation(predicate.with_self_ty(tcx, source))
+ ),
);
// We can only make objects from sized types.
- let tr = ty::TraitRef {
- def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
- substs: tcx.mk_substs_trait(source, &[]),
- };
+ let tr = ty::TraitRef::new(
+ tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
+ tcx.mk_substs_trait(source, &[]),
+ );
nested.push(predicate_to_obligation(tr.to_predicate()));
- // If the type is `Foo+'a`, ensures that the type
- // being cast to `Foo+'a` outlives `'a`:
+ // If the type is `Foo + 'a`, ensure that the type
+ // being cast to `Foo + 'a` outlives `'a`:
let outlives = ty::OutlivesPredicate(source, r);
nested.push(predicate_to_obligation(
ty::Binder::dummy(outlives).to_predicate(),
));
}
- // [T; n] -> [T].
+ // `[T; n]` -> `[T]`
(&ty::Array(a, _), &ty::Slice(b)) => {
let InferOk { obligations, .. } = self.infcx
.at(&obligation.cause, obligation.param_env)
nested.extend(obligations);
}
- // Struct<T> -> Struct<U>.
+ // `Struct<T>` -> `Struct<U>`
(&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
let fields = def.all_fields()
- .map(|f| tcx.type_of(f.did))
+ .map(|field| tcx.type_of(field.did))
.collect::<Vec<_>>();
// The last field of the structure has to exist and contain type parameters.
}
}
- // Extract Field<T> and Field<U> from Struct<T> and Struct<U>.
+ // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`.
let inner_source = field.subst(tcx, substs_a);
let inner_target = field.subst(tcx, substs_b);
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
- // Construct the nested Field<T>: Unsize<Field<U>> predicate.
+ // Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
nested.push(tcx.predicate_for_trait_def(
obligation.param_env,
obligation.cause.clone(),
));
}
- // (.., T) -> (.., U).
+ // `(.., T)` -> `(.., U)`
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
assert_eq!(tys_a.len(), tys_b.len());
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
- // Construct the nested T: Unsize<U> predicate.
+ // Construct the nested `T: Unsize<U>` predicate.
nested.push(tcx.predicate_for_trait_def(
obligation.param_env,
obligation.cause.clone(),
//
// This code is hot enough that it's worth avoiding the allocation
// required for the FxHashSet when possible. Special-casing lengths 0,
- // 1 and 2 covers roughly 75--80% of the cases.
+ // 1 and 2 covers roughly 75-80% of the cases.
if predicates.len() <= 1 {
// No possibility of duplicates.
} else if predicates.len() == 2 {
///////////////////////////////////////////////////////////////////////////
/// "Elaboration" is the process of identifying all the predicates that
-/// are implied by a source predicate. Currently this basically means
+/// are implied by a source predicate. Currently, this basically means
/// walking the "supertraits" and other similar assumptions. For example,
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
+use crate::hir;
use crate::hir::def_id::DefId;
use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
-use std::borrow::Cow;
-use std::fmt;
+
+use errors::{Applicability, DiagnosticBuilder};
use rustc_target::spec::abi;
use syntax::ast;
use syntax::errors::pluralize;
-use errors::{Applicability, DiagnosticBuilder};
use syntax_pos::Span;
-use crate::hir;
+use std::borrow::Cow;
+use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
pub struct ExpectedFound<T> {
ReifyShim(DefId),
/// `<fn() as FnTrait>::call_*`
- /// `DefId` is `FnTrait::call_*`
+ /// `DefId` is `FnTrait::call_*`.
FnPtrShim(DefId, Ty<'tcx>),
- /// `<Trait as Trait>::fn`
+ /// `<dyn Trait as Trait>::fn`
Virtual(DefId, usize),
/// `<[mut closure] as FnOnce>::call_once`
pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
let mut fn_sig = self.fn_sig_noadjust(tcx);
if let InstanceDef::VtableShim(..) = self.def {
- // Modify fn(self, ...) to fn(self: *mut Self, ...)
+ // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
fn_sig = fn_sig.map_bound(|mut fn_sig| {
let mut inputs_and_output = fn_sig.inputs_and_output.to_vec();
inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
assert!(i < this.fields.count());
- // Reuse the fat *T type as its own thin pointer data field.
- // This provides information about e.g., DST struct pointees
+ // Reuse the fat `*T` type as its own thin pointer data field.
+ // This provides information about, e.g., DST struct pointees
// (which may have no non-DST form), and will work as long
// as the `Abi` or `FieldPlacement` is checked by users.
if i == 0 {
}
}
-impl<'a> HashStable<StableHashingContext<'a>> for Variants {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- use crate::ty::layout::Variants::*;
- mem::discriminant(self).hash_stable(hcx, hasher);
-
- match *self {
- Single { index } => {
- index.hash_stable(hcx, hasher);
- }
- Multiple {
- ref discr,
- ref discr_kind,
- discr_index,
- ref variants,
- } => {
- discr.hash_stable(hcx, hasher);
- discr_kind.hash_stable(hcx, hasher);
- discr_index.hash_stable(hcx, hasher);
- variants.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for DiscriminantKind {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- use crate::ty::layout::DiscriminantKind::*;
- mem::discriminant(self).hash_stable(hcx, hasher);
-
- match *self {
- Tag => {}
- Niche {
- dataful_variant,
- ref niche_variants,
- niche_start,
- } => {
- dataful_variant.hash_stable(hcx, hasher);
- niche_variants.start().hash_stable(hcx, hasher);
- niche_variants.end().hash_stable(hcx, hasher);
- niche_start.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for FieldPlacement {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- use crate::ty::layout::FieldPlacement::*;
- mem::discriminant(self).hash_stable(hcx, hasher);
-
- match *self {
- Union(count) => {
- count.hash_stable(hcx, hasher);
- }
- Array { count, stride } => {
- count.hash_stable(hcx, hasher);
- stride.hash_stable(hcx, hasher);
- }
- Arbitrary { ref offsets, ref memory_index } => {
- offsets.hash_stable(hcx, hasher);
- memory_index.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for VariantIdx {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- self.as_u32().hash_stable(hcx, hasher)
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for Abi {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- use crate::ty::layout::Abi::*;
- mem::discriminant(self).hash_stable(hcx, hasher);
-
- match *self {
- Uninhabited => {}
- Scalar(ref value) => {
- value.hash_stable(hcx, hasher);
- }
- ScalarPair(ref a, ref b) => {
- a.hash_stable(hcx, hasher);
- b.hash_stable(hcx, hasher);
- }
- Vector { ref element, count } => {
- element.hash_stable(hcx, hasher);
- count.hash_stable(hcx, hasher);
- }
- Aggregate { sized } => {
- sized.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for Scalar {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let Scalar { value, ref valid_range } = *self;
- value.hash_stable(hcx, hasher);
- valid_range.start().hash_stable(hcx, hasher);
- valid_range.end().hash_stable(hcx, hasher);
- }
-}
-
-impl_stable_hash_for!(struct crate::ty::layout::Niche {
- offset,
- scalar
-});
-
-impl_stable_hash_for!(struct crate::ty::layout::LayoutDetails {
- variants,
- fields,
- abi,
- largest_niche,
- size,
- align
-});
-
-impl_stable_hash_for!(enum crate::ty::layout::Integer {
- I8,
- I16,
- I32,
- I64,
- I128
-});
-
-impl_stable_hash_for!(enum crate::ty::layout::Primitive {
- Int(integer, signed),
- F32,
- F64,
- Pointer
-});
-
-impl_stable_hash_for!(struct crate::ty::layout::AbiAndPrefAlign {
- abi,
- pref
-});
-
-impl<'tcx> HashStable<StableHashingContext<'tcx>> for Align {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
- self.bytes().hash_stable(hcx, hasher);
- }
-}
-
-impl<'tcx> HashStable<StableHashingContext<'tcx>> for Size {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
- self.bytes().hash_stable(hcx, hasher);
- }
-}
-
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
use crate::ty::layout::LayoutError::*;
///
/// These are all interned (by `intern_adt_def`) into the `adt_defs` table.
///
-/// The initialism *"Adt"* stands for an [*algebraic data type (ADT)*][adt].
+/// The initialism *ADT* stands for an [*algebraic data type (ADT)*][adt].
/// This is slightly wrong because `union`s are not ADTs.
/// Moreover, Rust only allows recursive data types through indirection.
///
/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type
pub struct AdtDef {
- /// `DefId` of the struct, enum or union item.
+ /// The `DefId` of the struct, enum or union item.
pub did: DefId,
/// Variants of the ADT. If this is a struct or union, then there will be a single variant.
pub variants: IndexVec<self::layout::VariantIdx, VariantDef>,
- /// Flags of the ADT (e.g. is this a struct? is this non-exhaustive?)
+ /// Flags of the ADT (e.g., is this a struct? is this non-exhaustive?).
flags: AdtFlags,
/// Repr options provided by the user.
pub repr: ReprOptions,
}
impl PartialEq for AdtDef {
- // AdtDef are always interned and this is part of TyS equality
+ // `AdtDef`s are always interned, and this is part of `TyS` equality.
#[inline]
fn eq(&self, other: &Self) -> bool { ptr::eq(self, other) }
}
impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx AdtDef {}
-
impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
thread_local! {
a: &ty::TraitRef<'tcx>,
b: &ty::TraitRef<'tcx>,
) -> RelateResult<'tcx, ty::TraitRef<'tcx>> {
- // Different traits cannot be related
+ // Different traits cannot be related.
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
a: &ty::ExistentialTraitRef<'tcx>,
b: &ty::ExistentialTraitRef<'tcx>,
) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> {
- // Different traits cannot be related
+ // Different traits cannot be related.
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
use crate::hir::def::Namespace;
use crate::mir::ProjectionKind;
+use crate::mir::interpret;
use crate::ty::{self, Lift, Ty, TyCtxt, InferConst};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::print::{FmtPrinter, Printer};
+
use rustc_index::vec::{IndexVec, Idx};
use smallvec::SmallVec;
-use crate::mir::interpret;
use std::fmt;
use std::rc::Rc;
#![allow(rustc::usage_of_ty_tykind)]
+use self::InferTy::*;
+use self::TyKind::*;
+
use crate::hir;
use crate::hir::def_id::DefId;
use crate::infer::canonical::Canonical;
use crate::mir::interpret::ConstValue;
use crate::middle::region;
-use polonius_engine::Atom;
-use rustc_index::vec::Idx;
-use rustc_macros::HashStable;
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, GenericArg, GenericArgKind};
use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
use crate::util::captures::Captures;
use crate::mir::interpret::{Scalar, GlobalId};
+use polonius_engine::Atom;
+use rustc_index::vec::Idx;
+use rustc_macros::HashStable;
+use rustc_target::spec::abi;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::marker::PhantomData;
use std::ops::Range;
-use rustc_target::spec::abi;
use syntax::ast::{self, Ident};
use syntax::symbol::{kw, Symbol};
-use self::InferTy::*;
-use self::TyKind::*;
-
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
+#[derive(
+ Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable,
+ HashStable, TypeFoldable, Lift,
+)]
pub struct TypeAndMut<'tcx> {
pub ty: Ty<'tcx>,
pub mutbl: hir::Mutability,
}
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
- RustcEncodable, RustcDecodable, Copy, HashStable)]
+#[derive(
+ Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, RustcDecodable, Copy, HashStable,
+)]
/// A "free" region `fr` can be interpreted as "some region
/// at least as big as the scope `fr.scope`".
pub struct FreeRegion {
pub bound_region: BoundRegion,
}
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
- RustcEncodable, RustcDecodable, Copy, HashStable)]
+#[derive(
+ Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, RustcDecodable, Copy, HashStable,
+)]
pub enum BoundRegion {
/// An anonymous region parameter for a given fn (&T)
BrAnon(u32),
}
impl<'tcx> GeneratorSubsts<'tcx> {
- /// Generator have not been resumed yet
+ /// Generator has not been resumed yet.
pub const UNRESUMED: usize = 0;
- /// Generator has returned / is completed
+ /// Generator has returned or is completed.
pub const RETURNED: usize = 1;
- /// Generator has been poisoned
+ /// Generator has been poisoned.
pub const POISONED: usize = 2;
const UNRESUMED_NAME: &'static str = "Unresumed";
const RETURNED_NAME: &'static str = "Returned";
const POISONED_NAME: &'static str = "Panicked";
- /// The valid variant indices of this Generator.
+ /// The valid variant indices of this generator.
#[inline]
pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> {
// FIXME requires optimized MIR
(VariantIdx::new(0)..VariantIdx::new(num_variants))
}
- /// The discriminant for the given variant. Panics if the variant_index is
+ /// The discriminant for the given variant. Panics if the `variant_index` is
/// out of range.
#[inline]
pub fn discriminant_for_variant(
Discr { val: variant_index.as_usize() as u128, ty: self.discr_ty(tcx) }
}
- /// The set of all discriminants for the Generator, enumerated with their
+ /// The set of all discriminants for the generator, enumerated with their
/// variant indices.
#[inline]
pub fn discriminants(
pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> {
match self[0] {
ExistentialPredicate::Trait(tr) => Some(tr),
- _ => None
+ _ => None,
}
}
pub fn principal_def_id(&self) -> Option<DefId> {
- self.principal().map(|d| d.def_id)
+ self.principal().map(|trait_ref| trait_ref.def_id)
}
#[inline]
{
self.iter().filter_map(|predicate| {
match *predicate {
- ExistentialPredicate::Projection(p) => Some(p),
+ ExistentialPredicate::Projection(projection) => Some(projection),
_ => None,
}
})
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
self.iter().filter_map(|predicate| {
match *predicate {
- ExistentialPredicate::AutoTrait(d) => Some(d),
- _ => None
+ ExistentialPredicate::AutoTrait(did) => Some(did),
+ _ => None,
}
})
}
}
pub fn iter<'a>(&'a self)
- -> impl DoubleEndedIterator<Item = Binder<ExistentialPredicate<'tcx>>> + 'tcx {
+ -> impl DoubleEndedIterator<Item = Binder<ExistentialPredicate<'tcx>>> + 'tcx
+ {
self.skip_binder().iter().cloned().map(Binder::bind)
}
}
impl<'tcx> TraitRef<'tcx> {
pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> TraitRef<'tcx> {
- TraitRef { def_id: def_id, substs: substs }
+ TraitRef { def_id, substs }
}
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
}
impl<'tcx> ExistentialTraitRef<'tcx> {
- pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'b {
+ pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'b {
// Select only the "input types" from a trait-reference. For
// now this is all the types that appear in the
// trait-reference, but it should eventually exclude
/// A region variable. Should not exist after typeck.
ReVar(RegionVid),
- /// A placeholder region - basically the higher-ranked version of ReFree.
+ /// A placeholder region -- basically, the higher-ranked version of `ReFree`.
/// Should not exist after typeck.
RePlaceholder(ty::PlaceholderRegion),
match self.kind {
Array(ty, _) | Slice(ty) => ty,
Str => tcx.mk_mach_uint(ast::UintTy::U8),
- _ => bug!("sequence_element_type called on non-sequence value: {}", self),
+ _ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
}
}
pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind {
Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs),
- _ => bug!("simd_type called on invalid type")
+ _ => bug!("`simd_type` called on invalid type"),
}
}
// allow `#[repr(simd)] struct Simd<T, const N: usize>([T; N]);`.
match self.kind {
Adt(def, _) => def.non_enum_variant().fields.len() as u64,
- _ => bug!("simd_size called on invalid type")
+ _ => bug!("`simd_size` called on invalid type"),
}
}
let variant = def.non_enum_variant();
(variant.fields.len() as u64, variant.fields[0].ty(tcx, substs))
}
- _ => bug!("simd_size_and_type called on invalid type")
+ _ => bug!("`simd_size_and_type` called on invalid type"),
}
}
}
}
- /// panics if called on any type other than `Box<T>`
+ /// Panics if called on any type other than `Box<T>`.
pub fn boxed_ty(&self) -> Ty<'tcx> {
match self.kind {
Adt(def, substs) if def.is_box() => substs.type_at(0),
}
/// If the type contains variants, returns the valid range of variant indices.
- /// FIXME This requires the optimized MIR in the case of generators.
+ //
+ // FIXME: This requires the optimized MIR in the case of generators.
#[inline]
pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
match self.kind {
/// If the type contains variants, returns the variant for `variant_index`.
/// Panics if `variant_index` is out of range.
- /// FIXME This requires the optimized MIR in the case of generators.
+ //
+ // FIXME: This requires the optimized MIR in the case of generators.
#[inline]
pub fn discriminant_for_variant(
&self,
}
}
- /// Push onto `out` the regions directly referenced from this type (but not
+ /// Pushes onto `out` the regions directly referenced from this type (but not
/// types reachable from this type via `walk_tys`). This ignores late-bound
/// regions binders.
pub fn push_regions(&self, out: &mut SmallVec<[ty::Region<'tcx>; 4]>) {
ty::Infer(ty::FreshTy(_)) |
ty::Infer(ty::FreshIntTy(_)) |
ty::Infer(ty::FreshFloatTy(_)) =>
- bug!("is_trivially_sized applied to unexpected type: {:?}", self),
+ bug!("`is_trivially_sized` applied to unexpected type: {:?}", self),
}
}
}
ty
}
- /// Same as applying struct_tail on `source` and `target`, but only
+ /// Same as applying `struct_tail` on `source` and `target`, but only
/// keeps going as long as the two types are instances of the same
/// structure definitions.
/// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
/// whereas struct_tail produces `T`, and `Trait`, respectively.
///
/// Should only be called if the types have no inference variables and do
- /// not need their lifetimes preserved (e.g. as part of codegen); otherwise
+ /// not need their lifetimes preserved (e.g., as part of codegen); otherwise,
/// normalization attempt may cause compiler bugs.
pub fn struct_lockstep_tails_erasing_lifetimes(self,
source: Ty<'tcx>,
source, target, |ty| tcx.normalize_erasing_regions(param_env, ty))
}
- /// Same as applying struct_tail on `source` and `target`, but only
+ /// Same as applying `struct_tail` on `source` and `target`, but only
/// keeps going as long as the two types are instances of the same
/// structure definitions.
/// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
-use crate::llvm::{self, AttributePlace};
use crate::builder::Builder;
use crate::context::CodegenCx;
+use crate::llvm::{self, AttributePlace};
use crate::type_::Type;
+use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
-use crate::type_of::{LayoutLlvmExt};
+
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::mir::operand::OperandValue;
-use rustc_target::abi::call::ArgAbi;
-
use rustc_codegen_ssa::traits::*;
-
+use rustc_target::abi::call::ArgAbi;
use rustc_target::abi::{HasDataLayout, LayoutOf};
use rustc::ty::{Ty};
use rustc::ty::layout::{self};
if self.is_sized_indirect() {
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
} else if self.is_unsized_indirect() {
- bug!("unsized ArgAbi must be handled through store_fn_arg");
+ bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
} else if let PassMode::Cast(cast) = self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align);
bx.lifetime_start(llscratch, scratch_size);
- // ...where we first store the value...
+ // ... where we first store the value...
bx.store(val, llscratch, scratch_align);
- // ...and then memcpy it to the intended destination.
+ // ... and then memcpy it to the intended destination.
bx.memcpy(
dst.llval,
self.layout.align.abi,
//! In order for link-time optimization to work properly, LLVM needs a unique
//! type identifier that tells it across compilation units which types are the
//! same as others. This type identifier is created by
-//! TypeMap::get_unique_type_id_of_type() using the following algorithm:
+//! `TypeMap::get_unique_type_id_of_type()` using the following algorithm:
//!
//! (1) Primitive types have their name as ID
//! (2) Structs, enums and traits have a multipart identifier
use super::namespace::mangled_name_of_instance;
use super::type_names::compute_debuginfo_type_name;
use super::CrateDebugContext;
-use crate::abi;
-use crate::value::Value;
-use rustc_codegen_ssa::traits::*;
+use crate::abi;
+use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::{DIArray, DIType, DIFile, DIScope, DIDescriptor,
DICompositeType, DILexicalBlock, DIFlags, DebugEmissionKind};
use crate::llvm_util;
+use crate::value::Value;
-use crate::common::CodegenCx;
+use rustc_codegen_ssa::traits::*;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def::CtorKind;
use rustc_fs_util::path_to_c_string;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_target::abi::HasDataLayout;
+use syntax::ast;
+use syntax::symbol::{Interner, Symbol};
+use syntax_pos::{self, Span, FileName};
use libc::{c_uint, c_longlong};
use std::collections::hash_map::Entry;
use std::iter;
use std::ptr;
use std::path::{Path, PathBuf};
-use syntax::ast;
-use syntax::symbol::{Interner, Symbol};
-use syntax_pos::{self, Span, FileName};
impl PartialEq for llvm::Metadata {
fn eq(&self, other: &Self) -> bool {
}
// From DWARF 5.
-// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1
+// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1.
const DW_LANG_RUST: c_uint = 0x1c;
#[allow(non_upper_case_globals)]
const DW_ATE_boolean: c_uint = 0x02;
#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
pub struct UniqueTypeId(ast::Name);
-// The TypeMap is where the CrateDebugContext holds the type metadata nodes
-// created so far. The metadata nodes are indexed by UniqueTypeId, and, for
-// faster lookup, also by Ty. The TypeMap is responsible for creating
-// UniqueTypeIds.
+/// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes
+/// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for
+/// faster lookup, also by `Ty`. The `TypeMap` is responsible for creating
+/// `UniqueTypeId`s.
#[derive(Default)]
pub struct TypeMap<'ll, 'tcx> {
- // The UniqueTypeIds created so far
+ /// The `UniqueTypeId`s created so far.
unique_id_interner: Interner,
- // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
+ /// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping.
unique_id_to_metadata: FxHashMap<UniqueTypeId, &'ll DIType>,
- // A map from types to debuginfo metadata. This is a N:1 mapping.
+ /// A map from types to debuginfo metadata. This is an N:1 mapping.
type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>,
- // A map from types to UniqueTypeId. This is a N:1 mapping.
+ /// A map from types to `UniqueTypeId`. This is an N:1 mapping.
type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>
}
impl TypeMap<'ll, 'tcx> {
- // Adds a Ty to metadata mapping to the TypeMap. The method will fail if
- // the mapping already exists.
+ /// Adds a Ty to metadata mapping to the TypeMap. The method will fail if
+ /// the mapping already exists.
fn register_type_with_metadata(
&mut self,
type_: Ty<'tcx>,
metadata: &'ll DIType,
) {
if self.type_to_metadata.insert(type_, metadata).is_some() {
- bug!("Type metadata for Ty '{}' is already in the TypeMap!", type_);
+ bug!("type metadata for `Ty` '{}' is already in the `TypeMap`!", type_);
}
}
- // Removes a Ty to metadata mapping
- // This is useful when computing the metadata for a potentially
- // recursive type (e.g. a function ptr of the form:
- //
- // fn foo() -> impl Copy { foo }
- //
- // This kind of type cannot be properly represented
- // via LLVM debuginfo. As a workaround,
- // we register a temporary Ty to metadata mapping
- // for the function before we compute its actual metadata.
- // If the metadata computation ends up recursing back to the
- // original function, it will use the temporary mapping
- // for the inner self-reference, preventing us from
- // recursing forever.
- //
- // This function is used to remove the temporary metadata
- // mapping after we've computed the actual metadata
+ /// Removes a `Ty`-to-metadata mapping.
+ /// This is useful when computing the metadata for a potentially
+ /// recursive type (e.g., a function pointer of the form:
+ ///
+ /// fn foo() -> impl Copy { foo }
+ ///
+ /// This kind of type cannot be properly represented
+ /// via LLVM debuginfo. As a workaround,
+ /// we register a temporary Ty to metadata mapping
+ /// for the function before we compute its actual metadata.
+ /// If the metadata computation ends up recursing back to the
+ /// original function, it will use the temporary mapping
+ /// for the inner self-reference, preventing us from
+ /// recursing forever.
+ ///
+ /// This function is used to remove the temporary metadata
+ /// mapping after we've computed the actual metadata.
fn remove_type(
&mut self,
type_: Ty<'tcx>,
) {
if self.type_to_metadata.remove(type_).is_none() {
- bug!("Type metadata Ty '{}' is not in the TypeMap!", type_);
+ bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", type_);
}
}
- // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will
- // fail if the mapping already exists.
+ /// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will
+ /// fail if the mapping already exists.
fn register_unique_id_with_metadata(
&mut self,
unique_type_id: UniqueTypeId,
metadata: &'ll DIType,
) {
if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() {
- bug!("Type metadata for unique id '{}' is already in the TypeMap!",
+ bug!("type metadata for unique ID '{}' is already in the `TypeMap`!",
self.get_unique_type_id_as_string(unique_type_id));
}
}
self.unique_id_to_metadata.get(&unique_type_id).cloned()
}
- // Get the string representation of a UniqueTypeId. This method will fail if
- // the id is unknown.
+ /// Gets the string representation of a `UniqueTypeId`. This method will fail if
+ /// the ID is unknown.
fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str {
let UniqueTypeId(interner_key) = unique_type_id;
self.unique_id_interner.get(interner_key)
}
- // Get the UniqueTypeId for the given type. If the UniqueTypeId for the given
- // type has been requested before, this is just a table lookup. Otherwise an
- // ID will be generated and stored for later lookup.
+ /// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given
+ /// type has been requested before, this is just a table lookup. Otherwise, an
+ /// ID will be generated and stored for later lookup.
fn get_unique_type_id_of_type<'a>(&mut self, cx: &CodegenCx<'a, 'tcx>,
type_: Ty<'tcx>) -> UniqueTypeId {
- // Let's see if we already have something in the cache
+ // Let's see if we already have something in the cache.
if let Some(unique_type_id) = self.type_to_unique_id.get(&type_).cloned() {
return unique_type_id;
}
- // if not, generate one
+ // If not, generate one.
// The hasher we are using to generate the UniqueTypeId. We want
// something that provides more than the 64 bits of the DefaultHasher.
return UniqueTypeId(key);
}
- // Get the UniqueTypeId for an enum variant. Enum variants are not really
- // types of their own, so they need special handling. We still need a
- // UniqueTypeId for them, since to debuginfo they *are* real types.
+ /// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really
+ /// types of their own, so they need special handling. We still need a
+ /// `UniqueTypeId` for them, since to debuginfo they *are* real types.
fn get_unique_type_id_of_enum_variant<'a>(&mut self,
cx: &CodegenCx<'a, 'tcx>,
enum_type: Ty<'tcx>,
UniqueTypeId(interner_key)
}
- // Get the unique type id string for an enum variant part.
- // Variant parts are not types and shouldn't really have their own id,
- // but it makes set_members_of_composite_type() simpler.
+ /// Gets the unique type ID string for an enum variant part.
+ /// Variant parts are not types and shouldn't really have their own ID,
+ /// but it makes `set_members_of_composite_type()` simpler.
fn get_unique_type_id_str_of_enum_variant_part(&mut self, enum_type_id: UniqueTypeId) -> &str {
let variant_part_type_id = format!("{}_variant_part",
self.get_unique_type_id_as_string(enum_type_id));
}
}
-// A description of some recursive type. It can either be already finished (as
-// with FinalMetadata) or it is not yet finished, but contains all information
-// needed to generate the missing parts of the description. See the
-// documentation section on Recursive Types at the top of this file for more
-// information.
+/// A description of some recursive type. It can either be already finished (as
+/// with `FinalMetadata`) or it is not yet finished, but contains all information
+/// needed to generate the missing parts of the description. See the
+/// documentation section on Recursive Types at the top of this file for more
+/// information.
enum RecursiveTypeDescription<'ll, 'tcx> {
UnfinishedMetadata {
unfinished_type: Ty<'tcx>,
member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
) -> RecursiveTypeDescription<'ll, 'tcx> {
- // Insert the stub into the TypeMap in order to allow for recursive references
+ // Insert the stub into the `TypeMap` in order to allow for recursive references.
let mut type_map = debug_context(cx).type_map.borrow_mut();
type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub);
type_map.register_type_with_metadata(unfinished_type, metadata_stub);
}
impl RecursiveTypeDescription<'ll, 'tcx> {
- // Finishes up the description of the type in question (mostly by providing
- // descriptions of the fields of the given type) and returns the final type
- // metadata.
+ /// Finishes up the description of the type in question (mostly by providing
+ /// descriptions of the fields of the given type) and returns the final type
+ /// metadata.
fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
match *self {
FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false),
// the TypeMap so that recursive references are possible. This
// will always be the case if the RecursiveTypeDescription has
// been properly created through the
- // create_and_register_recursive_type_forward_declaration()
+ // `create_and_register_recursive_type_forward_declaration()`
// function.
{
let type_map = debug_context(cx).type_map.borrow();
}
}
-// Returns from the enclosing function if the type metadata with the given
-// unique id can be found in the type map
+/// Returns from the enclosing function if the type metadata with the given
+/// unique ID can be found in the type map.
macro_rules! return_if_metadata_created_in_meantime {
($cx: expr, $unique_type_id: expr) => (
if let Some(metadata) = debug_context($cx).type_map
t: Ty<'tcx>,
usage_site_span: Span,
) -> &'ll DIType {
- // Get the unique type id of this type.
+ // Get the unique type ID of this type.
let unique_type_id = {
let mut type_map = debug_context(cx).type_map.borrow_mut();
- // First, try to find the type in TypeMap. If we have seen it before, we
+ // First, try to find the type in `TypeMap`. If we have seen it before, we
// can exit early here.
match type_map.find_metadata_for_type(t) {
Some(metadata) => {
return metadata;
},
None => {
- // The Ty is not in the TypeMap but maybe we have already seen
+ // The Ty is not in the `TypeMap` but maybe we have already seen
// an equivalent type (e.g., only differing in region arguments).
- // In order to find out, generate the unique type id and look
+ // In order to find out, generate the unique type ID and look
// that up.
let unique_type_id = type_map.get_unique_type_id_of_type(cx, t);
match type_map.find_metadata_for_unique_id(unique_type_id) {
//
// fn foo() -> impl Copy { foo }
//
- // See TypeMap::remove_type for more detals
- // about the workaround
+ // See `TypeMap::remove_type` for more detals
+ // about the workaround.
let temp_type = {
unsafe {
// The choice of type here is pretty arbitrary -
// anything reading the debuginfo for a recursive
// type is going to see *somthing* weird - the only
- // question is what exactly it will see
+ // question is what exactly it will see.
let (size, align) = cx.size_and_align_of(t);
llvm::LLVMRustDIBuilderCreateBasicType(
DIB(cx),
type_map.borrow_mut().remove_type(t);
- // This is actually a function pointer, so wrap it in pointer DI
+ // This is actually a function pointer, so wrap it in pointer DI.
MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
}
let mut type_map = debug_context(cx).type_map.borrow_mut();
if already_stored_in_typemap {
- // Also make sure that we already have a TypeMap entry for the unique type id.
+ // Also make sure that we already have a `TypeMap` entry for the unique type ID.
let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => metadata,
None => {
span_bug!(usage_site_span,
- "Expected type metadata for unique \
- type id '{}' to already be in \
- the debuginfo::TypeMap but it \
+ "expected type metadata for unique \
+ type ID '{}' to already be in \
+ the `debuginfo::TypeMap` but it \
was not. (Ty = {})",
type_map.get_unique_type_id_as_string(unique_type_id),
t);
Some(metadata) => {
if metadata != metadata_for_uid {
span_bug!(usage_site_span,
- "Mismatch between Ty and \
- UniqueTypeId maps in \
- debuginfo::TypeMap. \
+ "mismatch between `Ty` and \
+ `UniqueTypeId` maps in \
+ `debuginfo::TypeMap`. \
UniqueTypeId={}, Ty={}",
type_map.get_unique_type_id_as_string(unique_type_id),
t);
ty::Float(float_ty) => {
(float_ty.name_str(), DW_ATE_float)
},
- _ => bug!("debuginfo::basic_type_metadata - t is invalid type")
+ _ => bug!("debuginfo::basic_type_metadata - `t` is invalid type")
};
let (size, align) = cx.size_and_align_of(t);
};
// The OSX linker has an idiosyncrasy where it will ignore some debuginfo
- // if multiple object files with the same DW_AT_name are linked together.
+ // if multiple object files with the same `DW_AT_name` are linked together.
// As a workaround we generate unique names for each object file. Those do
// not correspond to an actual source file but that should be harmless.
if tcx.sess.target.target.options.is_like_osx {
//
// This should actually be
//
- // ```
- // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
- // ```
+ // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
//
- // that is, we should set LLVM's emission kind to `LineTablesOnly` if
+ // That is, we should set LLVM's emission kind to `LineTablesOnly` if
// we are compiling with "limited" debuginfo. However, some of the
// existing tools relied on slightly more debuginfo being generated than
// would be the case with `LineTablesOnly`, and we did not want to break
}
}
-// Description of a type member, which can either be a regular field (as in
-// structs or tuples) or an enum variant.
+/// Description of a type member, which can either be a regular field (as in
+/// structs or tuples) or an enum variant.
#[derive(Debug)]
struct MemberDescription<'ll> {
name: String,
}
}
-// A factory for MemberDescriptions. It produces a list of member descriptions
-// for some record-like type. MemberDescriptionFactories are used to defer the
-// creation of type member descriptions in order to break cycles arising from
-// recursive type definitions.
+/// A factory for `MemberDescription`s. It produces a list of member descriptions
+/// for some record-like type. `MemberDescriptionFactory`s are used to defer the
+/// creation of type member descriptions in order to break cycles arising from
+/// recursive type definitions.
enum MemberDescriptionFactory<'ll, 'tcx> {
StructMDF(StructMemberDescriptionFactory<'tcx>),
TupleMDF(TupleMemberDescriptionFactory<'tcx>),
// Structs
//=-----------------------------------------------------------------------------
-// Creates MemberDescriptions for the fields of a struct
+/// Creates `MemberDescription`s for the fields of a struct.
struct StructMemberDescriptionFactory<'tcx> {
ty: Ty<'tcx>,
variant: &'tcx ty::VariantDef,
// Tuples
//=-----------------------------------------------------------------------------
-// Creates MemberDescriptions for the fields of a tuple
+/// Creates `MemberDescription`s for the fields of a tuple.
struct TupleMemberDescriptionFactory<'tcx> {
ty: Ty<'tcx>,
component_types: Vec<Ty<'tcx>>,
// Enums
//=-----------------------------------------------------------------------------
-// DWARF variant support is only available starting in LLVM 8.
-// Although the earlier enum debug info output did not work properly
-// in all situations, it is better for the time being to continue to
-// sometimes emit the old style rather than emit something completely
-// useless when rust is compiled against LLVM 6 or older. LLVM 7
-// contains an early version of the DWARF variant support, and will
-// crash when handling the new debug info format. This function
-// decides which representation will be emitted.
+/// DWARF variant support is only available starting in LLVM 8.
+/// Although the earlier enum debug info output did not work properly
+/// in all situations, it is better for the time being to continue to
+/// sometimes emit the old style rather than emit something completely
+/// useless when rust is compiled against LLVM 6 or older. LLVM 7
+/// contains an early version of the DWARF variant support, and will
+/// crash when handling the new debug info format. This function
+/// decides which representation will be emitted.
fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
// On MSVC we have to use the fallback mode, because LLVM doesn't
// lower variant parts to PDB.
|| llvm_util::get_major_version() < 8;
}
-// Describes the members of an enum value: An enum is described as a union of
-// structs in DWARF. This MemberDescriptionFactory provides the description for
-// the members of this union; so for every variant of the given enum, this
-// factory will produce one MemberDescription (all with no name and a fixed
-// offset of zero bytes).
+/// Describes the members of an enum value; an enum is described as a union of
+/// structs in DWARF. This `MemberDescriptionFactory` provides the description for
+/// the members of this union; so for every variant of the given enum, this
+/// factory will produce one `MemberDescription` (all with no name and a fixed
+/// offset of zero bytes).
struct EnumMemberDescriptionFactory<'ll, 'tcx> {
enum_type: Ty<'tcx>,
layout: TyLayout<'tcx>,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
- // Create a description of the non-null variant
+ // Create a description of the non-null variant.
let (variant_type_metadata, member_description_factory) =
describe_enum_variant(cx,
variant,
}
}
-// Creates MemberDescriptions for the fields of a single enum variant.
+// Creates `MemberDescription`s for the fields of a single enum variant.
struct VariantMemberDescriptionFactory<'ll, 'tcx> {
- // Cloned from the layout::Struct describing the variant.
+ /// Cloned from the `layout::Struct` describing the variant.
offsets: Vec<layout::Size>,
args: Vec<(String, Ty<'tcx>)>,
discriminant_type_metadata: Option<&'ll DIType>,
}
}
-// Returns a tuple of (1) type_metadata_stub of the variant, (2) a
-// MemberDescriptionFactory for producing the descriptions of the
-// fields of the variant. This is a rudimentary version of a full
-// RecursiveTypeDescription.
+/// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
+/// `MemberDescriptionFactory` for producing the descriptions of the
+/// fields of the variant. This is a rudimentary version of a full
+/// `RecursiveTypeDescription`.
fn describe_enum_variant(
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyLayout<'tcx>,
}
}
-// Compute the type parameters for a type, if any, for the given
-// metadata.
+/// Computes the type parameters for a type, if any, for the given metadata.
fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> {
if let ty::Adt(def, substs) = ty.kind {
if !substs.types().next().is_none() {
}
}
-// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do
-// any caching, does not add any fields to the struct. This can be done later
-// with set_members_of_composite_type().
+/// A convenience wrapper around `LLVMRustDIBuilderCreateStructType()`. Does not do
+/// any caching, does not add any fields to the struct. This can be done later
+/// with `set_members_of_composite_type()`.
fn create_struct_stub(
cx: &CodegenCx<'ll, 'tcx>,
struct_type: Ty<'tcx>,
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
);
let metadata_stub = unsafe {
- // LLVMRustDIBuilderCreateStructType() wants an empty array. A null
+ // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
- // later on in llvm/lib/IR/Value.cpp.
+ // later on in `llvm/lib/IR/Value.cpp`.
let empty_array = create_DIArray(DIB(cx), &[]);
llvm::LLVMRustDIBuilderCreateStructType(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
);
let metadata_stub = unsafe {
- // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
+ // `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
- // later on in llvm/lib/IR/Value.cpp.
+ // later on in `llvm/lib/IR/Value.cpp`.
let empty_array = create_DIArray(DIB(cx), &[]);
llvm::LLVMRustDIBuilderCreateUnionType(
}
let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE);
- // We may want to remove the namespace scope if we're in an extern block, see:
- // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952
+ // We may want to remove the namespace scope if we're in an extern block (see
+ // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
let var_scope = get_namespace_for_item(cx, def_id);
let span = tcx.def_span(def_id);
let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP);
unsafe {
- // LLVMRustDIBuilderCreateStructType() wants an empty array. A null
+ // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
- // later on in llvm/lib/IR/Value.cpp.
+ // later on in `llvm/lib/IR/Value.cpp`.
let empty_array = create_DIArray(DIB(cx), &[]);
let name = const_cstr!("vtable");
- // Create a new one each time. We don't want metadata caching
+ // Create a new one each time. We don't want metadata caching
// here, because each vtable will refer to a unique containing
// type.
let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
}
}
-// Creates an "extension" of an existing DIScope into another file.
+/// Creates an "extension" of an existing `DIScope` into another file.
pub fn extend_scope_to_file(
cx: &CodegenCx<'ll, '_>,
scope_metadata: &'ll DIScope,
match scalar.value {
Primitive::Int(..) => {
if self.cx().size_of(ret_ty).bytes() < 4 {
- // va_arg should not be called on a integer type
+ // `va_arg` should not be called on a integer type
// less than 4 bytes in length. If it is, promote
// the integer to a `i32` and truncate the result
// back to the smaller type.
//! Codegen the completed AST to the LLVM IR.
//!
-//! Some functions here, such as codegen_block and codegen_expr, return a value --
-//! the result of the codegen to LLVM -- while others, such as codegen_fn
-//! and mono_item, are called only for the side effect of adding a
+//! Some functions here, such as `codegen_block` and `codegen_expr`, return a value --
+//! the result of the codegen to LLVM -- while others, such as `codegen_fn`
+//! and `mono_item`, are called only for the side effect of adding a
//! particular definition to the LLVM IR output we're producing.
//!
//! Hopefully useful general knowledge about codegen:
//!
-//! * There's no way to find out the `Ty` type of a Value. Doing so
+//! * There's no way to find out the `Ty` type of a `Value`. Doing so
//! would be "trying to get the eggs out of an omelette" (credit:
//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`,
//! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
-use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen};
+use crate::{CachedModuleCodegen, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
+use crate::back::write::{
+ OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm,
+ submit_post_lto_module_to_llvm,
+};
+use crate::common::{RealPredicate, TypeKind, IntPredicate};
+use crate::meth;
+use crate::mir;
+use crate::mir::operand::OperandValue;
+use crate::mir::place::PlaceRef;
+use crate::traits::*;
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
+use rustc::hir;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::cstore::EncodedMetadata;
use rustc::middle::lang_items::StartFnLangItem;
use rustc::mir::mono::{CodegenUnitNameBuilder, CodegenUnit, MonoItem};
use rustc::ty::{self, Ty, TyCtxt, Instance};
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
+use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
use rustc::ty::query::Providers;
use rustc::middle::cstore::{self, LinkagePreference};
use rustc::util::common::{time, print_time_passes_entry, set_time_depth, time_depth};
use rustc::util::nodemap::FxHashMap;
use rustc_index::vec::Idx;
use rustc_codegen_utils::{symbol_names_test, check_for_rustc_errors_attr};
-use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
-use crate::mir::place::PlaceRef;
-use crate::back::write::{OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm,
- submit_post_lto_module_to_llvm};
-use crate::{MemFlags, CrateInfo};
-use crate::common::{RealPredicate, TypeKind, IntPredicate};
-use crate::meth;
-use crate::mir;
-
-use crate::traits::*;
+use syntax::attr;
+use syntax_pos::Span;
use std::cmp;
use std::ops::{Deref, DerefMut};
use std::time::{Instant, Duration};
-use syntax_pos::Span;
-use syntax::attr;
-use rustc::hir;
-
-use crate::mir::operand::OperandValue;
pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind,
signed: bool)
/// Retrieves the information we are losing (making dynamic) in an unsizing
/// adjustment.
///
-/// The `old_info` argument is a bit funny. It is intended for use
-/// in an upcast, where the new vtable for an object will be derived
-/// from the old one.
+/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
+/// where the new vtable for an object will be derived from the old one.
pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
cx: &Cx,
source: Ty<'tcx>,
(_, &ty::Dynamic(ref data, ..)) => {
let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target))
.field(cx, FAT_PTR_EXTRA);
- cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()),
- cx.backend_type(vtable_ptr))
+ cx.const_ptrcast(
+ meth::get_vtable(cx, source, data.principal()),
+ cx.backend_type(vtable_ptr),
+ )
}
- _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
- source,
- target),
+ _ => bug!(
+ "unsized_info: invalid unsizing {:?} -> {:?}",
+ source, target
+ ),
}
}
-/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
+/// Coerces `src` to `dst_ty`. `src_ty` must be a thin pointer.
pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
src: Bx::Value,
}
}
-/// Coerce `src`, which is a reference to a value of type `src_ty`,
-/// to a value of type `dst_ty` and store the result in `dst`
+/// Coerces `src`, which is a reference to a value of type `src_ty`,
+/// to a value of type `dst_ty`, and stores the result in `dst`.
pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
src: PlaceRef<'tcx, Bx::Value>,
if src_f.layout.ty == dst_f.layout.ty {
memcpy_ty(bx, dst_f.llval, dst_f.align, src_f.llval, src_f.align,
- src_f.layout, MemFlags::empty());
+ src_f.layout, MemFlags::empty());
} else {
coerce_unsized_into(bx, src_f, dst_f);
}
}
}
- _ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}",
- src_ty,
- dst_ty),
+ _ => bug!(
+ "coerce_unsized_into: invalid coercion {:?} -> {:?}",
+ src_ty,
+ dst_ty,
+ ),
}
}
-use rustc_target::abi::call::FnAbi;
-
use crate::traits::*;
use rustc::ty::{self, Ty, Instance};
+use rustc_target::abi::call::FnAbi;
#[derive(Copy, Clone, Debug)]
pub struct VirtualIndex(u64);
self,
bx: &mut Bx,
llvtable: Bx::Value,
- fn_abi: &FnAbi<'tcx, Ty<'tcx>>
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> Bx::Value {
// Load the data pointer from the object.
debug!("get_fn({:?}, {:?})", llvtable, self);
let gep = bx.inbounds_gep(llvtable, &[bx.const_usize(self.0)]);
let ptr = bx.load(gep, ptr_align);
bx.nonnull_metadata(ptr);
- // Vtable loads are invariant
+ // Vtable loads are invariant.
bx.set_invariant_load(ptr);
ptr
}
pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
self,
bx: &mut Bx,
- llvtable: Bx::Value
+ llvtable: Bx::Value,
) -> Bx::Value {
// Load the data pointer from the object.
debug!("get_int({:?}, {:?})", llvtable, self);
let usize_align = bx.tcx().data_layout.pointer_align.abi;
let gep = bx.inbounds_gep(llvtable, &[bx.const_usize(self.0)]);
let ptr = bx.load(gep, usize_align);
- // Vtable loads are invariant
+ // Vtable loads are invariant.
bx.set_invariant_load(ptr);
ptr
}
///
/// The `trait_ref` encodes the erased self type. Hence if we are
/// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then
-/// `trait_ref` would map `T:Trait`.
+/// `trait_ref` would map `T: Trait`.
pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
cx: &Cx,
ty: Ty<'tcx>,
return val;
}
- // Not in the cache. Build it.
+ // Not in the cache; build it.
let nullptr = cx.const_null(cx.type_i8p());
let methods_root;
let layout = cx.layout_of(ty);
// /////////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to
- // `get_vtable` in rust_mir/interpret/traits.rs
+ // `get_vtable` in `rust_mir/interpret/traits.rs`.
// /////////////////////////////////////////////////////////////////////////////////////////////
let components: Vec<_> = [
cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
use rustc::ty::layout::{self, HasTyCtxt};
use syntax::source_map::Span;
use crate::traits::*;
+use crate::mir::operand::OperandRef;
use super::FunctionCx;
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+ pub fn eval_mir_constant_to_operand(
+ &mut self,
+ bx: &mut Bx,
+ constant: &mir::Constant<'tcx>,
+ ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
+ match constant.literal.val {
+ ty::ConstKind::Unevaluated(def_id, substs)
+ if self.cx.tcx().is_static(def_id) => {
+ assert!(substs.is_empty(), "we don't support generic statics yet");
+ let static_ = bx.get_static(def_id);
+ // we treat operands referring to statics as if they were `&STATIC` instead
+ let ptr_ty = self.cx.tcx().mk_mut_ptr(self.monomorphize(&constant.literal.ty));
+ let layout = bx.layout_of(ptr_ty);
+ Ok(OperandRef::from_immediate_or_packed_pair(bx, static_, layout))
+ }
+ _ => {
+ let val = self.eval_mir_constant(constant)?;
+ Ok(OperandRef::from_const(bx, val))
+ }
+ }
+ }
+
pub fn eval_mir_constant(
&mut self,
constant: &mir::Constant<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
match constant.literal.val {
- ty::ConstKind::Unevaluated(def_id, ref substs) => {
- let substs = self.monomorphize(substs);
+ ty::ConstKind::Unevaluated(def_id, substs) => {
+ let substs = self.monomorphize(&substs);
let instance = ty::Instance::resolve(
self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs,
).unwrap();
-use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
-use rustc::mir;
-use rustc::ty;
-use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
+use super::{FunctionCx, LocalRef};
+use super::place::PlaceRef;
-use crate::base;
use crate::MemFlags;
+use crate::base;
use crate::glue;
-
use crate::traits::*;
-use std::fmt;
+use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
+use rustc::mir;
+use rustc::ty;
+use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size};
-use super::{FunctionCx, LocalRef};
-use super::place::PlaceRef;
+use std::fmt;
/// The representation of a Rust value. The enum variant is in fact
/// uniquely determined by the value's type, but is kept as a
}
}
}
+
pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
self,
bx: &mut Bx,
}
mir::Operand::Constant(ref constant) => {
- self.eval_mir_constant(constant)
- .map(|c| OperandRef::from_const(bx, c))
+ self.eval_mir_constant_to_operand(bx, constant)
.unwrap_or_else(|err| {
match err {
// errored or at least linted
-use rustc::ty::{self, Instance, Ty};
-use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
-use rustc::mir;
-use rustc::mir::tcx::PlaceTy;
+use super::{FunctionCx, LocalRef};
+use super::operand::OperandValue;
+
use crate::MemFlags;
use crate::common::IntPredicate;
use crate::glue;
-
use crate::traits::*;
-use super::{FunctionCx, LocalRef};
-use super::operand::OperandValue;
+use rustc::ty::{self, Instance, Ty};
+use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
+use rustc::mir;
+use rustc::mir::tcx::PlaceTy;
#[derive(Copy, Clone, Debug)]
pub struct PlaceRef<'tcx, V> {
- /// Pointer to the contents of the place.
+ /// A pointer to the contents of the place.
pub llval: V,
- /// This place's extra data if it is unsized, or null.
+ /// This place's extra data if it is unsized, or `None` if null.
pub llextra: Option<V>,
- /// Monomorphized type of this place, including variant information.
+ /// The monomorphized type of this place, including variant information.
pub layout: TyLayout<'tcx>,
- /// What alignment we know for this place.
+ /// The alignment we know for this place.
pub align: Align,
}
bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout)
}
}
-
}
impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
+use super::{FunctionCx, LocalRef};
+use super::operand::{OperandRef, OperandValue};
+use super::place::PlaceRef;
+
+use crate::base;
+use crate::MemFlags;
+use crate::common::{self, RealPredicate, IntPredicate};
+use crate::traits::*;
+
use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
use rustc::mir;
use rustc::middle::lang_items::ExchangeMallocFnLangItem;
use rustc_apfloat::{ieee, Float, Status, Round};
-use std::{u128, i128};
use syntax::symbol::sym;
use syntax::source_map::{DUMMY_SP, Span};
-use crate::base;
-use crate::MemFlags;
-use crate::common::{self, RealPredicate, IntPredicate};
-
-use crate::traits::*;
-
-use super::{FunctionCx, LocalRef};
-use super::operand::{OperandRef, OperandValue};
-use super::place::PlaceRef;
+use std::{u128, i128};
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn codegen_rvalue(
match *rvalue {
mir::Rvalue::Use(ref operand) => {
let cg_operand = self.codegen_operand(&mut bx, operand);
- // FIXME: consider not copying constants through stack. (fixable by codegenning
- // constants into OperandValue::Ref, why don’t we do that yet if we don’t?)
+ // FIXME: consider not copying constants through stack. (Fixable by codegen'ing
+ // constants into `OperandValue::Ref`; why don’t we do that yet if we don’t?)
cg_operand.val.store(&mut bx, dest);
bx
}
// The destination necessarily contains a fat pointer, so if
// it's a scalar pair, it's a fat pointer or newtype thereof.
if bx.cx().is_backend_scalar_pair(dest.layout) {
- // into-coerce of a thin pointer to a fat pointer - just
+ // Into-coerce of a thin pointer to a fat pointer -- just
// use the operand path.
let (mut bx, temp) = self.codegen_rvalue_operand(bx, rvalue);
temp.val.store(&mut bx, dest);
match operand.val {
OperandValue::Pair(..) |
OperandValue::Immediate(_) => {
- // unsize from an immediate structure. We don't
+ // Unsize from an immediate structure. We don't
// really need a temporary alloca here, but
// avoiding it would require us to have
- // `coerce_unsized_into` use extractvalue to
+ // `coerce_unsized_into` use `extractvalue` to
// index into the struct, and this case isn't
// important enough for it.
debug!("codegen_rvalue: creating ugly alloca");
base::coerce_unsized_into(&mut bx, source, dest);
}
OperandValue::Ref(_, Some(_), _) => {
- bug!("unsized coercion on an unsized rvalue")
+ bug!("unsized coercion on an unsized rvalue");
}
}
bx
bx
}
- _ => bug!("unsized assignment other than Rvalue::Use"),
+ _ => bug!("unsized assignment other than `Rvalue::Use`"),
}
}
}
}
mir::CastKind::Pointer(PointerCast::UnsafeFnPointer) => {
- // this is a no-op at the LLVM level
+ // This is a no-op at the LLVM level.
operand.val
}
mir::CastKind::Pointer(PointerCast::Unsize) => {
assert!(bx.cx().is_backend_scalar_pair(cast));
match operand.val {
OperandValue::Pair(lldata, llextra) => {
- // unsize from a fat pointer - this is a
+ // unsize from a fat pointer -- this is a
// "trait-object-to-supertrait" coercion, for
- // example,
- // &'a fmt::Debug+Send => &'a fmt::Debug,
+ // example, `&'a fmt::Debug + Send => &'a fmt::Debug`.
// HACK(eddyb) have to bitcast pointers
// until LLVM removes pointee types.
OperandValue::Pair(lldata, llextra)
}
OperandValue::Ref(..) => {
- bug!("by-ref operand {:?} in codegen_rvalue_operand",
+ bug!("by-ref operand {:?} in `codegen_rvalue_operand`",
operand);
}
}
}
- mir::CastKind::Pointer(PointerCast::MutToConstPointer)
- | mir::CastKind::Misc if bx.cx().is_backend_scalar_pair(operand.layout) => {
+ mir::CastKind::Pointer(PointerCast::MutToConstPointer) |
+ mir::CastKind::Misc if bx.cx().is_backend_scalar_pair(operand.layout) => {
if let OperandValue::Pair(data_ptr, meta) = operand.val {
if bx.cx().is_backend_scalar_pair(cast) {
let data_cast = bx.pointercast(data_ptr,
OperandValue::Immediate(llval)
}
} else {
- bug!("Unexpected non-Pair operand")
+ bug!("unexpected non-pair operand");
}
}
- mir::CastKind::Pointer(PointerCast::MutToConstPointer)
- | mir::CastKind::Pointer(PointerCast::ArrayToPointer)
- | mir::CastKind::Misc => {
+ mir::CastKind::Pointer(PointerCast::MutToConstPointer) |
+ mir::CastKind::Pointer(PointerCast::ArrayToPointer) |
+ mir::CastKind::Misc => {
assert!(bx.cx().is_backend_immediate(cast));
let ll_t_out = bx.cx().immediate_backend_type(cast);
if operand.layout.abi.is_uninhabited() {
-use rustc::ty::layout::{HasTyCtxt, LayoutOf, TyLayout};
-use rustc::ty::Ty;
-
use super::write::WriteBackendMethods;
use super::CodegenObject;
+
+use rustc::ty::layout::{HasTyCtxt, LayoutOf, TyLayout};
+use rustc::ty::Ty;
use rustc::middle::cstore::EncodedMetadata;
use rustc::session::{Session, config};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use std::sync::Arc;
-use std::sync::mpsc;
use syntax::expand::allocator::AllocatorKind;
use syntax_pos::symbol::Symbol;
+use std::sync::Arc;
+use std::sync::mpsc;
+
pub trait BackendTypes {
type Value: CodegenObject;
type Function: CodegenObject;
use super::intrinsic::IntrinsicCallMethods;
use super::type_::ArgAbiMethods;
use super::{HasCodegen, StaticBuilderMethods};
+
use crate::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate,
SynchronizationScope};
use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
use crate::MemFlags;
+
use rustc::ty::Ty;
use rustc::ty::layout::{Align, Size, HasParamEnv};
-use rustc_target::spec::{HasTargetSpec};
+use rustc_target::spec::HasTargetSpec;
+
use std::ops::Range;
use std::iter::TrustedLen;
ArgAbiMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
};
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
-use rustc::ty::layout::{HasParamEnv, HasTyCtxt};
-use rustc_target::spec::{HasTargetSpec};
+use rustc::ty::layout::{HasParamEnv, HasTyCtxt};
+use rustc_target::spec::HasTargetSpec;
use std::fmt;
}
}
+impl<T, CTX> HashStable<CTX> for ::std::ops::RangeInclusive<T>
+ where T: HashStable<CTX>
+{
+ #[inline]
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.start().hash_stable(ctx, hasher);
+ self.end().hash_stable(ctx, hasher);
+ }
+}
+
impl<I: vec::Idx, T, CTX> HashStable<CTX> for vec::IndexVec<I, T>
where T: HashStable<CTX>,
{
compiler.parse()?;
- if let Some((ppm, opt_uii)) = &sess.opts.pretty {
- if ppm.needs_ast_map(&opt_uii) {
+ if let Some(ppm) = &sess.opts.pretty {
+ if ppm.needs_ast_map() {
compiler.global_ctxt()?.peek_mut().enter(|tcx| {
let expanded_crate = compiler.expansion()?.take().0;
pretty::print_after_hir_lowering(
compiler.input(),
&expanded_crate,
*ppm,
- opt_uii.clone(),
compiler.output_file().as_ref().map(|p| &**p),
);
Ok(())
use rustc::hir::print as pprust_hir;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::session::Session;
-use rustc::session::config::{PpMode, PpSourceMode, UserIdentifiedItem, Input};
+use rustc::session::config::{PpMode, PpSourceMode, Input};
use rustc::ty::{self, TyCtxt};
use rustc::util::common::ErrorReported;
use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
use std::io::Write;
use std::path::Path;
-pub use self::UserIdentifiedItem::*;
pub use self::PpSourceMode::*;
pub use self::PpMode::*;
use crate::abort_on_err;
input: &Input,
krate: &ast::Crate,
ppm: PpMode,
- opt_uii: Option<UserIdentifiedItem>,
ofile: Option<&Path>,
) {
if ppm.needs_analysis() {
abort_on_err(print_with_analysis(
tcx,
ppm,
- opt_uii,
ofile
), tcx.sess);
return;
let mut out = String::new();
- match (ppm, opt_uii) {
- (PpmSource(s), _) => {
+ match ppm {
+ PpmSource(s) => {
// Silently ignores an identified node.
let out = &mut out;
let src = src.clone();
})
}
- (PpmHir(s), None) => {
+ PpmHir(s) => {
let out = &mut out;
let src = src.clone();
call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
})
}
- (PpmHirTree(s), None) => {
+ PpmHirTree(s) => {
let out = &mut out;
call_with_pp_support_hir(&s, tcx, move |_annotation, krate| {
debug!("pretty printing source code {:?}", s);
});
}
- (PpmHir(s), Some(uii)) => {
- let out = &mut out;
- let src = src.clone();
- call_with_pp_support_hir(&s, tcx, move |annotation, _| {
- debug!("pretty printing source code {:?}", s);
- let sess = annotation.sess();
- let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map");
- let mut pp_state = pprust_hir::State::new_from_input(sess.source_map(),
- &sess.parse_sess,
- src_name,
- src,
- annotation.pp_ann());
- for node_id in uii.all_matching_node_ids(hir_map) {
- let hir_id = tcx.hir().node_to_hir_id(node_id);
- let node = hir_map.get(hir_id);
- pp_state.print_node(node);
- pp_state.s.space();
- let path = annotation.node_path(hir_id)
- .expect("-Z unpretty missing node paths");
- pp_state.synth_comment(path);
- pp_state.s.hardbreak();
- }
- *out = pp_state.s.eof();
- })
- }
-
- (PpmHirTree(s), Some(uii)) => {
- let out = &mut out;
- call_with_pp_support_hir(&s, tcx, move |_annotation, _krate| {
- debug!("pretty printing source code {:?}", s);
- for node_id in uii.all_matching_node_ids(tcx.hir()) {
- let hir_id = tcx.hir().node_to_hir_id(node_id);
- let node = tcx.hir().get(hir_id);
- out.push_str(&format!("{:#?}", node));
- }
- })
- }
-
_ => unreachable!(),
}
fn print_with_analysis(
tcx: TyCtxt<'_>,
ppm: PpMode,
- uii: Option<UserIdentifiedItem>,
ofile: Option<&Path>,
) -> Result<(), ErrorReported> {
- let nodeid = if let Some(uii) = uii {
- debug!("pretty printing for {:?}", uii);
- Some(uii.to_one_node_id("-Z unpretty", tcx.sess, tcx.hir()))
- } else {
- debug!("pretty printing for whole crate");
- None
- };
-
let mut out = Vec::new();
tcx.analysis(LOCAL_CRATE)?;
match ppm {
PpmMir | PpmMirCFG => {
- let def_id = nodeid.map(|nid| tcx.hir().local_def_id_from_node_id(nid));
match ppm {
- PpmMir => write_mir_pretty(tcx, def_id, &mut out),
- PpmMirCFG => write_mir_graphviz(tcx, def_id, &mut out),
+ PpmMir => write_mir_pretty(tcx, None, &mut out),
+ PpmMirCFG => write_mir_graphviz(tcx, None, &mut out),
_ => unreachable!(),
}
}
-The only functions that can be called in static or constant expressions are
-`const` functions, and struct/enum constructors. `const` functions are only
-available on a nightly compiler. Rust currently does not support more general
-compile-time function execution.
+A constant item was initialized with something that is not a constant expression.
+
+Erroneous code example:
+
+```compile_fail,E0015
+fn create_some() -> Option<u8> {
+ Some(1)
+}
+const FOO: Option<u8> = create_some(); // error!
```
-const FOO: Option<u8> = Some(1); // enum constructor
-struct Bar {x: u8}
-const BAR: Bar = Bar {x: 1}; // struct constructor
+
+The only functions that can be called in static or constant expressions are
+`const` functions, and struct/enum constructors.
+
+To fix this error, you can declare `create_some` as a constant function:
+
```
+const fn create_some() -> Option<u8> { // declared as a const function
+ Some(1)
+}
-See [RFC 911] for more details on the design of `const fn`s.
+const FOO: Option<u8> = create_some(); // ok!
-[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+// These are also working:
+struct Bar {
+ x: u8,
+}
+
+const OTHER_FOO: Option<u8> = Some(1);
+const BAR: Bar = Bar {x: 1};
+```
Erroneous code example:
-```
+```compile_fail,E0023
enum Fruit {
Apple(String, String),
Pear(u32),
}
+
+let x = Fruit::Apple(String::new(), String::new());
+
+match x {
+ Fruit::Apple(a) => {}, // error!
+ _ => {}
+}
```
A pattern used to match against an enum variant must provide a sub-pattern for
You can read more about trait objects in the [Trait Objects] section of the
Reference.
-[Trait Objects]: https://doc.rust-lang.org/reference/types.html#trait-objects
\ No newline at end of file
+[Trait Objects]: https://doc.rust-lang.org/reference/types.html#trait-objects
In such a case, the compiler cannot predict the return type of `foo()` in a
situation like the following:
-```compile_fail
+```compile_fail,E0038
trait Trait {
fn foo(&self) -> Self;
}
We don't just need to create a table of all implementations of all methods of
`Trait`, we need to create such a table, for each different type fed to
-`foo()`. In this case this turns out to be (10 types implementing `Trait`)*(3
+`foo()`. In this case this turns out to be (10 types implementing `Trait`)\*(3
types being fed to `foo()`) = 30 implementations!
With real world traits these numbers can grow drastically.
-When invoking closures or other implementations of the function traits `Fn`,
-`FnMut` or `FnOnce` using call notation, the number of parameters passed to the
-function must match its definition.
+An invalid number of arguments was given when calling a closure.
-An example using a closure:
+Erroneous code example:
```compile_fail,E0057
let f = |x| x * 3;
let c = f(2, 3); // invalid, too many parameters
```
+When invoking closures or other implementations of the function traits `Fn`,
+`FnMut` or `FnOnce` using call notation, the number of parameters passed to the
+function must match its definition.
+
A generic function must be treated similarly:
```
+An invalid number of arguments was passed when calling a function.
+
+Erroneous code example:
+
+```compile_fail,E0061
+fn f(u: i32) {}
+
+f(); // error!
+```
+
The number of arguments passed to a function must match the number of arguments
specified in the function signature.
}));
msg.push((format!("`{}", found_extra), Style::NoStyle));
- // For now, just attach these as notes
+ // For now, just attach these as notes.
self.highlighted_note(msg);
self
}
use syntax::token;
use syntax::source_map::{FileName, FileLoader, SourceMap};
use syntax::sess::ParseSess;
-use syntax_expand::config::process_configure_mod;
use syntax_pos::edition;
pub type Result<T> = result::Result<T, ErrorReported>;
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
syntax::with_default_globals(move || {
let cfg = cfgspecs.into_iter().map(|s| {
- let sess = ParseSess::with_silent_emitter(process_configure_mod);
+ let sess = ParseSess::with_silent_emitter();
let filename = FileName::cfg_spec_source_code(&s);
let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
// If we're actually rustdoc then there's no need to actually compile
// anything, so switch everything to just looping
let mut should_loop = sess.opts.actually_rustdoc;
- if let Some((PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops), _)) = sess.opts.pretty {
+ if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
should_loop |= true;
}
if should_loop {
use syntax::symbol::sym;
use syntax::edition::{Edition, DEFAULT_EDITION};
use syntax;
-use syntax_expand::config::process_configure_mod;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{ColorConfig, emitter::HumanReadableErrorType, registry};
fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
let registry = registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
- let sess = build_session(sessopts, None, registry, process_configure_mod);
+ let sess = build_session(sessopts, None, registry);
(sess, cfg)
}
use syntax::source_map::{FileLoader, RealFileLoader, SourceMap};
use syntax::symbol::{Symbol, sym};
use syntax::{self, ast, attr};
-use syntax_expand::config::process_configure_mod;
use syntax_pos::edition::Edition;
#[cfg(not(parallel_compiler))]
use std::{thread, panic};
source_map.clone(),
diagnostic_output,
lint_caps,
- process_configure_mod,
);
sess.prof.register_queries(|profiler| {
attrs
}
+pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+ let generic: syn::GenericParam = parse_quote!(__CTX);
+ s.add_bounds(synstructure::AddBounds::Generics);
+ s.add_impl_generic(generic);
+ let body = s.each(|bi| {
+ let attrs = parse_attributes(bi.ast());
+ if attrs.ignore {
+ quote!{}
+ } else if let Some(project) = attrs.project {
+ quote!{
+ &#bi.#project.hash_stable(__hcx, __hasher);
+ }
+ } else {
+ quote!{
+ #bi.hash_stable(__hcx, __hasher);
+ }
+ }
+ });
+
+ let discriminant = match s.ast().data {
+ syn::Data::Enum(_) => quote! {
+ ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
+ },
+ syn::Data::Struct(_) => quote! {},
+ syn::Data::Union(_) => panic!("cannot derive on union"),
+ };
+
+ s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>), quote!{
+ fn hash_stable(
+ &self,
+ __hcx: &mut __CTX,
+ __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
+ #discriminant
+ match *self { #body }
+ }
+ })
+}
+
pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
let generic: syn::GenericParam = parse_quote!('__ctx);
s.add_bounds(synstructure::AddBounds::Generics);
}
decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
+decl_derive!(
+ [HashStable_Generic, attributes(stable_hasher)] =>
+ hash_stable::hash_stable_generic_derive
+);
+
decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive);
decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
arena = { path = "../libarena" }
either = "1.5.0"
dot = { path = "../libgraphviz", package = "graphviz" }
+itertools = "0.8"
log = "0.4"
log_settings = "0.1.1"
polonius-engine = "0.10.0"
location: mir::Location,
) {
if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
- if borrowed_place.ignore_borrow(
- self.tcx, self.body, &self.locals_state_at_exit) {
+ if borrowed_place.ignore_borrow(self.tcx, self.body, &self.locals_state_at_exit) {
+ debug!("ignoring_borrow of {:?}", borrowed_place);
return;
}
use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
use rustc::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
- FakeReadCause, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef,
- ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+ FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
+ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
};
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashSet;
projection: root_place_projection,
}, borrow_span));
+ if let PlaceBase::Local(local) = borrow.borrowed_place.base {
+ if self.body.local_decls[local].is_ref_to_thread_local() {
+ let err = self.report_thread_local_value_does_not_live_long_enough(
+ drop_span,
+ borrow_span,
+ );
+ err.buffer(&mut self.errors_buffer);
+ return;
+ }
+ };
+
if let StorageDeadOrDrop::Destructor(dropped_ty) =
self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
{
explanation
);
let err = match (place_desc, explanation) {
- (Some(_), _) if self.is_place_thread_local(root_place) => {
- self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
- }
// If the outlives constraint comes from inside the closure,
// for example:
//
// place being assigned later.
let (place_description, assigned_span) = match local_decl {
Some(LocalDecl {
- is_user_variable: Some(ClearCrossCrate::Clear),
+ local_info: LocalInfo::User(ClearCrossCrate::Clear),
..
})
| Some(LocalDecl {
- is_user_variable:
- Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
- opt_match_place: None,
- ..
- }))),
+ local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+ opt_match_place: None,
+ ..
+ }))),
+ ..
+ })
+ | Some(LocalDecl {
+ local_info: LocalInfo::StaticRef { .. },
..
})
| Some(LocalDecl {
- is_user_variable: None,
+ local_info: LocalInfo::Other,
..
})
| None => (self.describe_place(place.as_ref()), assigned_span),
use rustc::hir::def_id::DefId;
use rustc::hir::GeneratorKind;
use rustc::mir::{
- AggregateKind, Constant, Field, Local, LocalKind, Location, Operand,
+ AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand,
Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
Static, StaticKind, Terminator, TerminatorKind,
};
use rustc::ty::print::Print;
use rustc_errors::DiagnosticBuilder;
use syntax_pos::Span;
-use syntax::symbol::sym;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
} => {
buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
}
+ PlaceRef {
+ base: &PlaceBase::Local(local),
+ projection: [ProjectionElem::Deref]
+ } if self.body.local_decls[local].is_ref_for_guard() => {
+ self.append_place_to_string(
+ PlaceRef {
+ base: &PlaceBase::Local(local),
+ projection: &[],
+ },
+ buf,
+ autoderef,
+ &including_downcast,
+ )?;
+ },
+ PlaceRef {
+ base: &PlaceBase::Local(local),
+ projection: [ProjectionElem::Deref]
+ } if self.body.local_decls[local].is_ref_to_static() => {
+ let local_info = &self.body.local_decls[local].local_info;
+ if let LocalInfo::StaticRef { def_id, .. } = *local_info {
+ buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
+ } else {
+ unreachable!();
+ }
+ },
PlaceRef {
base,
projection: [proj_base @ .., elem],
)?;
} else {
match (proj_base, base) {
- ([], PlaceBase::Local(local)) => {
- if self.body.local_decls[*local].is_ref_for_guard() {
- self.append_place_to_string(
- PlaceRef {
- base,
- projection: proj_base,
- },
- buf,
- autoderef,
- &including_downcast,
- )?;
- } else {
- // FIXME deduplicate this and the _ => body below
- buf.push_str(&"*");
- self.append_place_to_string(
- PlaceRef {
- base,
- projection: proj_base,
- },
- buf,
- autoderef,
- &including_downcast,
- )?;
- }
- }
-
_ => {
buf.push_str(&"*");
self.append_place_to_string(
}
}
- /// Checks if a place is a thread-local static.
- pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool {
- if let PlaceRef {
- base: PlaceBase::Static(box Static {
- kind: StaticKind::Static,
- def_id,
- ..
- }),
- projection: [],
- } = place_ref {
- let attrs = self.infcx.tcx.get_attrs(*def_id);
- let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
-
- debug!(
- "is_place_thread_local: attrs={:?} is_thread_local={:?}",
- attrs, is_thread_local
- );
- is_thread_local
- } else {
- debug!("is_place_thread_local: no");
- false
- }
- }
-
/// Add a note that a type does not implement `Copy`
pub(super) fn note_type_does_not_implement_copy(
&self,
// would have a chance of erroneously adding non-user-defined mutable vars
// to the set.
let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter()
- .filter(|&local| mbcx.body.local_decls[*local].is_user_variable.is_none())
+ .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
.cloned()
.collect();
// For the remaining unused locals that are marked as mutable, we avoid linting any that
match *operand {
Operand::Move(ref place) | Operand::Copy(ref place) => {
match place.as_local() {
- Some(local) if self.body.local_decls[local].is_user_variable.is_none() => {
+ Some(local) if !self.body.local_decls[local].is_user_variable() => {
if self.body.local_decls[local].ty.is_mutable_ptr() {
// The variable will be marked as mutable by the borrow.
return;
) {
debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = &borrow.borrowed_place;
- let root_place = self.prefixes(place.as_ref(), PrefixSet::All).last().unwrap();
+ let deref = [ProjectionElem::Deref];
+ let mut root_place = PlaceRef { base: &place.base, projection: &[] };
// FIXME(nll-rfc#40): do more precise destructor tracking here. For now
// we just know that all locals are dropped at function exit (otherwise
//
// FIXME: allow thread-locals to borrow other thread locals?
- assert!(root_place.projection.is_empty());
let (might_be_alive, will_be_dropped) = match root_place.base {
- PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(..),
- ..
- }) => {
+ PlaceBase::Static(_) => {
(true, false)
}
- PlaceBase::Static(box Static {
- kind: StaticKind::Static,
- ..
- }) => {
- // Thread-locals might be dropped after the function exits, but
- // "true" statics will never be.
- (true, self.is_place_thread_local(root_place))
- }
- PlaceBase::Local(_) => {
- // Locals are always dropped at function exit, and if they
- // have a destructor it would've been called already.
- (false, self.locals_are_invalidated_at_exit)
+ PlaceBase::Local(local) => {
+ if self.body.local_decls[*local].is_ref_to_thread_local() {
+ // Thread-locals might be dropped after the function exits
+ // We have to dereference the outer reference because
+ // borrows don't conflict behind shared references.
+ root_place.projection = &deref;
+ (true, true)
+ } else {
+ (false, self.locals_are_invalidated_at_exit)
+ }
}
};
let error_access;
let the_place_err;
- // rust-lang/rust#21232, #54986: during period where we reject
- // partial initialization, do not complain about mutability
- // errors except for actual mutation (as opposed to an attempt
- // to do a partial initialization).
- let previously_initialized = if let PlaceBase::Local(local) = place.base {
- self.is_local_ever_initialized(local, flow_state).is_some()
- } else {
- true
- };
-
match kind {
Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
| Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. }))
}
}
+ // rust-lang/rust#21232, #54986: during period where we reject
+ // partial initialization, do not complain about mutability
+ // errors except for actual mutation (as opposed to an attempt
+ // to do a partial initialization).
+ let previously_initialized = if let PlaceBase::Local(local) = place.base {
+ self.is_local_ever_initialized(local, flow_state).is_some()
+ } else {
+ true
+ };
+
// at this point, we have set up the error reporting state.
- return if previously_initialized {
+ if previously_initialized {
self.report_mutability_error(
place,
span,
true
} else {
false
- };
+ }
}
fn is_local_ever_initialized(
//
// opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression
- if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
- opt_match_place: Some((ref opt_match_place, match_span)),
- binding_mode: _,
- opt_ty_info: _,
- pat_span: _,
- }))) = local_decl.is_user_variable
- {
+ if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm {
+ opt_match_place: Some((ref opt_match_place, match_span)),
+ binding_mode: _,
+ opt_ty_info: _,
+ pat_span: _,
+ },
+ ))) = local_decl.local_info {
let stmt_source_info = self.body.source_info(location);
self.append_binding_error(
grouped_errors,
(
match kind {
IllegalMoveOriginKind::Static => {
- self.report_cannot_move_from_static(original_path, span)
+ unreachable!();
}
IllegalMoveOriginKind::BorrowedContent { target_place } => {
self.report_cannot_move_from_borrowed_content(
place: &Place<'tcx>,
span: Span
) -> DiagnosticBuilder<'a> {
- let description = if place.projection.is_empty() {
+ let description = if place.projection.len() == 1 {
format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
} else {
let base_static = PlaceRef {
base: &place.base,
- projection: &place.projection[..1],
+ projection: &[ProjectionElem::Deref],
};
format!(
"variables bound in patterns cannot be moved from \
until after the end of the pattern guard");
return err;
+ } else if decl.is_ref_to_static() {
+ return self.report_cannot_move_from_static(move_place, span);
}
}
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
for local in binds_to {
let bind_to = &self.body.local_decls[*local];
- if let Some(
+ if let LocalInfo::User(
ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
pat_span,
..
}))
- ) = bind_to.is_user_variable {
+ ) = bind_to.local_info {
if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
{
if pat_snippet.starts_with('&') {
use rustc::hir;
use rustc::hir::Node;
-use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Body};
-use rustc::mir::{
- Mutability, Place, PlaceRef, PlaceBase, ProjectionElem, Static, StaticKind
-};
+use rustc::mir::{self, Body, ClearCrossCrate, Local, LocalInfo, Location};
+use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_index::vec::Idx;
use syntax_pos::Span;
}
}
+ PlaceRef {
+ base: &PlaceBase::Local(local),
+ projection: [ProjectionElem::Deref],
+ } if self.body.local_decls[local].is_ref_for_guard() => {
+ item_msg = format!("`{}`", access_place_desc.unwrap());
+ reason = ", as it is immutable for the pattern guard".to_string();
+ }
+ PlaceRef {
+ base: &PlaceBase::Local(local),
+ projection: [ProjectionElem::Deref],
+ } if self.body.local_decls[local].is_ref_to_static() => {
+ if access_place.projection.len() == 1 {
+ item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+ reason = String::new();
+ } else {
+ item_msg = format!("`{}`", access_place_desc.unwrap());
+ let local_info = &self.body.local_decls[local].local_info;
+ if let LocalInfo::StaticRef { def_id, .. } = *local_info {
+ let static_name = &self.infcx.tcx.item_name(def_id);
+ reason = format!(", as `{}` is an immutable static item", static_name);
+ } else {
+ bug!("is_ref_to_static return true, but not ref to static?");
+ }
+ }
+ }
PlaceRef {
base: _,
projection: [proj_base @ .., ProjectionElem::Deref],
} else {
", as `Fn` closures cannot mutate their captured variables".to_string()
}
- } else if {
- if let (PlaceBase::Local(local), []) = (&the_place_err.base, proj_base) {
- self.body.local_decls[*local].is_ref_for_guard()
- } else {
- false
- }
- } {
- item_msg = format!("`{}`", access_place_desc.unwrap());
- reason = ", as it is immutable for the pattern guard".to_string();
} else {
let source = self.borrowed_content_source(PlaceRef {
base: the_place_err.base,
}
PlaceRef {
- base:
- PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(..),
- ..
- }),
- projection: [],
- } => unreachable!(),
-
- PlaceRef {
- base:
- PlaceBase::Static(box Static {
- kind: StaticKind::Static,
- def_id,
- ..
- }),
- projection: [],
- } => {
- if let PlaceRef {
- base: &PlaceBase::Static(_),
- projection: &[],
- } = access_place.as_ref() {
- item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
- reason = String::new();
- } else {
- item_msg = format!("`{}`", access_place_desc.unwrap());
- let static_name = &self.infcx.tcx.item_name(*def_id);
- reason = format!(", as `{}` is an immutable static item", static_name);
- }
+ base: PlaceBase::Static(_),
+ ..
}
-
- PlaceRef {
+ | PlaceRef {
base: _,
projection: [.., ProjectionElem::Index(_)],
}
projection: [],
} if {
self.body.local_decls.get(*local).map(|local_decl| {
- if let ClearCrossCrate::Set(
+ if let LocalInfo::User(ClearCrossCrate::Set(
mir::BindingForm::ImplicitSelf(kind)
- ) = local_decl.is_user_variable.as_ref().unwrap() {
+ )) = local_decl.local_info {
// Check if the user variable is a `&mut self` and we can therefore
// suggest removing the `&mut`.
//
// Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them.
- *kind == mir::ImplicitSelfKind::MutRef
+ kind == mir::ImplicitSelfKind::MutRef
} else if Some(kw::SelfLower) == local_decl.name {
// Otherwise, check if the name is the self kewyord - in which case
// we have an explicit self. Do the same thing in this case and check
PlaceRef {
base: PlaceBase::Local(local),
projection: [ProjectionElem::Deref],
- } if {
- if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
- self.body.local_decls[*local].is_user_variable
- {
- true
- } else {
- false
- }
- } =>
- {
+ } if self.body.local_decls[*local].is_ref_for_guard() => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
err.note(
"variables bound in patterns are immutable until the end of the pattern guard",
PlaceRef {
base: PlaceBase::Local(local),
projection: [ProjectionElem::Deref],
- } if self.body.local_decls[*local].is_user_variable.is_some() =>
+ } if self.body.local_decls[*local].is_user_variable() =>
{
let local_decl = &self.body.local_decls[*local];
- let suggestion = match local_decl.is_user_variable.as_ref().unwrap() {
- ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_)) => {
+ let suggestion = match local_decl.local_info {
+ LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_))) => {
Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
}
- ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
- binding_mode: ty::BindingMode::BindByValue(_),
- opt_ty_info,
- ..
- })) => Some(suggest_ampmut(
+ LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+ mir::VarBindingForm {
+ binding_mode: ty::BindingMode::BindByValue(_),
+ opt_ty_info,
+ ..
+ },
+ ))) => Some(suggest_ampmut(
self.infcx.tcx,
self.body,
*local,
local_decl,
- *opt_ty_info,
+ opt_ty_info,
)),
- ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
- binding_mode: ty::BindingMode::BindByReference(_),
- ..
- })) => {
+ LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+ mir::VarBindingForm {
+ binding_mode: ty::BindingMode::BindByReference(_),
+ ..
+ },
+ ))) => {
let pattern_span = local_decl.source_info.span;
suggest_ref_mut(self.infcx.tcx, pattern_span)
.map(|replacement| (pattern_span, replacement))
}
- ClearCrossCrate::Set(mir::BindingForm::RefForGuard) => unreachable!(),
+ LocalInfo::User(ClearCrossCrate::Clear) => bug!("saw cleared local state"),
- ClearCrossCrate::Clear => bug!("saw cleared local state"),
+ _ => unreachable!(),
};
let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() {
} else {
ConstraintCategory::Return
},
- Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
+ Some(l) if !body.local_decls[l].is_user_variable() => {
ConstraintCategory::Boring
}
_ => ConstraintCategory::Assignment,
ConstraintCategory::Return
}
}
- Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
+ Some(l) if !body.local_decls[l].is_user_variable() => {
ConstraintCategory::Boring
}
_ => ConstraintCategory::Assignment,
use rustc::hir;
use rustc::mir::ProjectionElem;
-use rustc::mir::{Body, Place, PlaceBase, Mutability, Static, StaticKind};
+use rustc::mir::{Body, Place, PlaceBase, Mutability};
use rustc::ty::{self, TyCtxt};
use crate::borrow_check::borrow_set::LocalsStateAtExit;
body: &Body<'tcx>,
locals_state_at_exit: &LocalsStateAtExit,
) -> bool {
- let ignore = match self.base {
+ let local = match self.base {
// If a local variable is immutable, then we only need to track borrows to guard
// against two kinds of errors:
// * The variable being dropped while still borrowed (e.g., because the fn returns
//
// In particular, the variable cannot be mutated -- the "access checks" will fail --
// so we don't have to worry about mutation while borrowed.
- PlaceBase::Local(index) => {
+ PlaceBase::Local(local) => {
match locals_state_at_exit {
- LocalsStateAtExit::AllAreInvalidated => false,
+ LocalsStateAtExit::AllAreInvalidated => local,
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
- let ignore = !has_storage_dead_or_moved.contains(index) &&
- body.local_decls[index].mutability == Mutability::Not;
- debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
- ignore
+ let ignore = !has_storage_dead_or_moved.contains(local) &&
+ body.local_decls[local].mutability == Mutability::Not;
+ debug!("ignore_borrow: local {:?} => {:?}", local, ignore);
+ if ignore {
+ return true;
+ } else {
+ local
+ }
}
}
}
- PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
- false,
- PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
- tcx.is_mutable_static(def_id)
- }
+ PlaceBase::Static(_) => return true,
};
for (i, elem) in self.projection.iter().enumerate() {
if *elem == ProjectionElem::Deref {
let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
- if let ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Immutable) = ty.kind {
- // For both derefs of raw pointers and `&T`
- // references, the original path is `Copy` and
- // therefore not significant. In particular,
- // there is nothing the user can do to the
- // original path that would invalidate the
- // newly created reference -- and if there
- // were, then the user could have copied the
- // original path into a new variable and
- // borrowed *that* one, leaving the original
- // path unborrowed.
- return true;
+ match ty.kind {
+ ty::Ref(_, _, hir::Mutability::Immutable) if i == 0 => {
+ // For references to thread-local statics, we do need
+ // to track the borrow.
+ if body.local_decls[local].is_ref_to_thread_local() {
+ continue;
+ }
+ return true;
+ }
+ ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Immutable) => {
+ // For both derefs of raw pointers and `&T`
+ // references, the original path is `Copy` and
+ // therefore not significant. In particular,
+ // there is nothing the user can do to the
+ // original path that would invalidate the
+ // newly created reference -- and if there
+ // were, then the user could have copied the
+ // original path into a new variable and
+ // borrowed *that* one, leaving the original
+ // path unborrowed.
+ return true;
+ }
+ _ => {}
}
}
}
- ignore
+ false
}
}
literal,
}
},
+ ExprKind::StaticRef { literal, .. } => {
+ Constant {
+ span,
+ user_ty: None,
+ literal,
+ }
+ }
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
}
}
};
block.and(place_builder)
}
- ExprKind::StaticRef { id } => block.and(PlaceBuilder::from(
- PlaceBase::Static(Box::new(Static {
- ty: expr.ty,
- kind: StaticKind::Static,
- def_id: id,
- }))
- )),
ExprKind::PlaceTypeAscription { source, user_ty } => {
let source = this.hir.mirror(source);
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
| ExprKind::Literal { .. }
+ | ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::Yield { .. }
| ExprKind::Call { .. } => {
resume.and(this.unit_rvalue())
}
ExprKind::Literal { .. }
+ | ExprKind::StaticRef { .. }
| ExprKind::Block { .. }
| ExprKind::Match { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
| ExprKind::InlineAsm { .. }
- | ExprKind::StaticRef { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => {
// these do not have corresponding `Rvalue` variants,
use rustc::hir;
use rustc::middle::region;
use rustc::mir::*;
+use syntax_pos::symbol::sym;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr` into a fresh temporary. This is used when building
if let Some(tail_info) = this.block_context.currently_in_block_tail() {
local_decl = local_decl.block_tail(tail_info);
}
+ if let ExprKind::StaticRef { def_id, .. } = expr.kind {
+ let is_thread_local = this.hir.tcx().has_attr(def_id, sym::thread_local);
+ local_decl.local_info = LocalInfo::StaticRef {def_id, is_thread_local };
+ }
this.local_decls.push(local_decl)
};
let temp_place = &Place::from(temp);
| ExprKind::Index { .. }
| ExprKind::SelfRef
| ExprKind::VarRef { .. }
- | ExprKind::StaticRef { .. }
| ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
| ExprKind::Yield { .. }
| ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
- ExprKind::Literal { .. } => Some(Category::Constant),
+ ExprKind::Literal { .. }
+ | ExprKind::StaticRef { .. } => Some(Category::Constant),
ExprKind::Loop { .. }
| ExprKind::Block { .. }
source_info,
visibility_scope: source_info.scope,
internal: true,
- is_user_variable: None,
+ local_info: LocalInfo::Other,
is_block_tail: None,
});
let ptr_temp = Place::from(ptr_temp);
// Avoid creating a temporary
ExprKind::VarRef { .. } |
ExprKind::SelfRef |
- ExprKind::StaticRef { .. } |
ExprKind::PlaceTypeAscription { .. } |
ExprKind::ValueTypeAscription { .. } => {
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
| ExprKind::Tuple { .. }
| ExprKind::Closure { .. }
| ExprKind::Literal { .. }
+ | ExprKind::StaticRef { .. }
| ExprKind::Yield { .. } => {
debug_assert!(match Category::of(&expr.kind).unwrap() {
// should be handled above
for binding in &candidate.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
- if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+ if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
opt_match_place: Some((ref mut match_place, _)),
..
- }))) = self.local_decls[local].is_user_variable
+ }))) = self.local_decls[local].local_info
{
*match_place = Some(initializer.clone());
} else {
visibility_scope,
internal: false,
is_block_tail: None,
- is_user_variable: Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
- binding_mode,
- // hypothetically, `visit_bindings` could try to unzip
- // an outermost hir::Ty as we descend, matching up
- // idents in pat; but complex w/ unclear UI payoff.
- // Instead, just abandon providing diagnostic info.
- opt_ty_info: None,
- opt_match_place,
- pat_span,
- }))),
+ local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm {
+ binding_mode,
+ // hypothetically, `visit_bindings` could try to unzip
+ // an outermost hir::Ty as we descend, matching up
+ // idents in pat; but complex w/ unclear UI payoff.
+ // Instead, just abandon providing diagnostic info.
+ opt_ty_info: None,
+ opt_match_place,
+ pat_span,
+ },
+ ))),
};
let for_arm_body = self.local_decls.push(local);
let locals = if has_guard.0 {
visibility_scope,
internal: false,
is_block_tail: None,
- is_user_variable: Some(ClearCrossCrate::Set(BindingForm::RefForGuard)),
+ local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)),
});
LocalsForNode::ForGuard {
ref_for_guard,
visibility_scope: source_info.scope,
name,
internal: false,
- is_user_variable: None,
+ local_info: LocalInfo::Other,
is_block_tail: None,
});
}
} => {
self.local_decls[local].mutability = mutability;
self.local_decls[local].source_info.scope = self.source_scope;
- self.local_decls[local].is_user_variable =
+ self.local_decls[local].local_info =
if let Some(kind) = self_binding {
- Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
+ LocalInfo::User(ClearCrossCrate::Set(
+ BindingForm::ImplicitSelf(*kind),
+ ))
} else {
let binding_mode = ty::BindingMode::BindByValue(mutability.into());
- Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
- binding_mode,
- opt_ty_info,
- opt_match_place: Some((Some(place.clone()), span)),
- pat_span: span,
- })))
+ LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm {
+ binding_mode,
+ opt_ty_info,
+ opt_match_place: Some((Some(place.clone()), span)),
+ pat_span: span,
+ },
+ )))
};
self.var_indices.insert(var, LocalsForNode::One(local));
}
// local must conflict. This is purely an optimization so we don't have to call
// `places_conflict` for every borrow.
if place.projection.is_empty() {
- trans.kill_all(other_borrows_of_local);
+ if !self.body.local_decls[local].is_ref_to_static() {
+ trans.kill_all(other_borrows_of_local);
+ }
return;
}
use crate::hair::{self, *};
use crate::hair::cx::Cx;
use crate::hair::cx::to_ref::ToRef;
+
use rustc::middle::region;
use rustc::hir;
use rustc::ty;
use crate::hair::util::UserAnnotatedTyHelpers;
use rustc_index::vec::Idx;
use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind};
-use rustc::mir::interpret::{GlobalId, ErrorHandled};
+use rustc::mir::interpret::{GlobalId, ErrorHandled, Scalar};
use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, PointerCast};
use rustc::ty::subst::{InternalSubsts, SubstsRef};
}
}
- Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id },
+ // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
+ // a constant reference (or constant raw pointer for `static mut`) in MIR
+ Res::Def(DefKind::Static, id) => {
+ let ty = cx.tcx.type_of(id);
+ let ty = if cx.tcx.is_mutable_static(id) {
+ cx.tcx.mk_mut_ptr(ty)
+ } else if cx.tcx.is_foreign_item(id) {
+ cx.tcx.mk_imm_ptr(ty)
+ } else {
+ cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_static, ty)
+ };
+ let ptr = cx.tcx.alloc_map.lock().create_static_alloc(id);
+ let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ ExprKind::Deref { arg: Expr {
+ ty,
+ temp_lifetime,
+ span: expr.span,
+ kind: ExprKind::StaticRef {
+ literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty),
+ def_id: id,
+ }
+ }.to_ref() }
+ },
Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
},
/// first argument, used for self in a closure
SelfRef,
- StaticRef {
- id: DefId,
- },
Borrow {
borrow_kind: BorrowKind,
arg: ExprRef<'tcx>,
literal: &'tcx Const<'tcx>,
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
},
+ /// A literal containing the address of a `static`.
+ ///
+ /// This is only distinguished from `Literal` so that we can register some
+ /// info for diagnostics.
+ StaticRef {
+ literal: &'tcx Const<'tcx>,
+ def_id: DefId,
+ },
InlineAsm {
asm: &'tcx hir::InlineAsmInner,
outputs: Vec<ExprRef<'tcx>>,
#[derive(Debug, Copy, Clone)]
pub enum AllocCheck {
/// Allocation must be live and not a function pointer.
- Dereferencable,
+ Dereferenceable,
/// Allocations needs to be live, but may be a function pointer.
Live,
/// Allocation may be dead.
}
Err(ptr) => {
let (allocation_size, alloc_align) =
- self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferencable)?;
+ self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
// Test bounds. This also ensures non-NULL.
// It is sufficient to check this for the end pointer. The addition
// checks for overflow.
// # Function pointers
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
if let Ok(_) = self.get_fn_alloc(id) {
- return if let AllocCheck::Dereferencable = liveness {
+ return if let AllocCheck::Dereferenceable = liveness {
// The caller requested no function pointers.
throw_unsup!(DerefFunctionPointer)
} else {
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct OpTy<'tcx, Tag=()> {
- op: Operand<Tag>, // Keep this private, it helps enforce invariants
+ op: Operand<Tag>, // Keep this private; it helps enforce invariants.
pub layout: TyLayout<'tcx>,
}
if cfg!(debug_assertions) {
let layout2 = compute()?;
assert_eq!(layout.details, layout2.details,
- "Mismatch in layout of supposedly equal-layout types {:?} and {:?}",
+ "mismatch in layout of supposedly equal-layout types {:?} and {:?}",
layout.ty, layout2.ty);
}
Ok(layout)
#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx, Tag=()> {
- place: Place<Tag>, // Keep this private, it helps enforce invariants
+ place: Place<Tag>, // Keep this private; it helps enforce invariants.
pub layout: TyLayout<'tcx>,
}
+use super::{InterpCx, Machine, MemoryKind, FnVal};
+
use rustc::ty::{self, Ty, Instance, TypeFoldable};
use rustc::ty::layout::{Size, Align, LayoutOf, HasDataLayout};
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
-use super::{InterpCx, Machine, MemoryKind, FnVal};
-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
/// objects.
///
- /// The `trait_ref` encodes the erased self type. Hence if we are
+ /// The `trait_ref` encodes the erased self type. Hence, if we are
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
- /// `trait_ref` would map `T:Trait`.
+ /// `trait_ref` would map `T: Trait`.
pub fn get_vtable(
&mut self,
ty: Ty<'tcx>,
let ptr_align = self.tcx.data_layout.pointer_align.abi;
// /////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to
- // `get_vtable` in rust_codegen_llvm/meth.rs
+ // `get_vtable` in `rust_codegen_llvm/meth.rs`.
// /////////////////////////////////////////////////////////////////////////////////////////
let vtable = self.memory.allocate(
ptr_size * (3 + methods.len() as u64),
Ok(vtable)
}
- /// Resolve the function at the specified slot in the provided
+ /// Resolves the function at the specified slot in the provided
/// vtable. An index of '0' corresponds to the first method
- /// declared in the trait of the provided vtable
+ /// declared in the trait of the provided vtable.
pub fn get_vtable_slot(
&self,
vtable: Scalar<M::PointerTag>,
idx: usize
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
let ptr_size = self.pointer_size();
- // Skip over the 'drop_ptr', 'size', and 'align' fields
+ // Skip over the 'drop_ptr', 'size', and 'align' fields.
let vtable_slot = vtable.ptr_offset(ptr_size * (idx as u64 + 3), self)?;
let vtable_slot = self.memory.check_ptr_access(
vtable_slot,
Ok(self.memory.get_fn(fn_ptr)?)
}
- /// Returns the drop fn instance as well as the actual dynamic type
+ /// Returns the drop fn instance as well as the actual dynamic type.
pub fn read_drop_type_from_vtable(
&self,
vtable: Scalar<M::PointerTag>,
) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
- // we don't care about the pointee type, we just want a pointer
+ // We don't care about the pointee type; we just want a pointer.
let vtable = self.memory.check_ptr_access(
vtable,
self.tcx.data_layout.pointer_size,
vtable: Scalar<M::PointerTag>,
) -> InterpResult<'tcx, (Size, Align)> {
let pointer_size = self.pointer_size();
- // We check for size = 3*ptr_size, that covers the drop fn (unused here),
+ // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
// the size, and the align (which we read below).
let vtable = self.memory.check_ptr_access(
vtable,
"non-integer slice length in wide pointer", self.path);
// We do not check that `len * elem_size <= isize::MAX`:
// that is only required for references, and there it falls out of the
- // "dereferencable" check performed by Stacked Borrows.
+ // "dereferenceable" check performed by Stacked Borrows.
}
ty::Foreign(..) => {
// Unsized, but not wide.
if place.layout.is_unsized() {
self.check_wide_ptr_meta(place.meta, place.layout)?;
}
- // Make sure this is dereferencable and all.
+ // Make sure this is dereferenceable and all.
let (size, align) = self.ecx.size_and_align_of(place.meta, place.layout)?
// for the purpose of validity, consider foreign types to have
// alignment and size determined by the layout (size will be 0,
#![feature(decl_macro)]
#![feature(drain_filter)]
#![feature(exhaustive_patterns)]
+#![feature(iter_order_by)]
#![cfg_attr(bootstrap, feature(never_type))]
#![feature(specialization)]
#![feature(try_trait)]
//! Mono Item Collection
-//! ===========================
+//! ====================
//!
//! This module is responsible for discovering all items that will contribute to
//! to code generation of the crate. The important part here is that it not only
//! this is not implemented however: a mono item will be produced
//! regardless of whether it is actually needed or not.
+use crate::monomorphize;
+
use rustc::hir::{self, CodegenFnAttrFlags};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
-
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::mir::visit::Visitor as MirVisitor;
use rustc::mir::mono::{MonoItem, InstantiationMode};
use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled};
-
-use crate::monomorphize;
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
use rustc::util::common::time;
}
impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
-
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
debug!("visiting rvalue {:?}", *rvalue);
}
}
PlaceBase::Local(_) => {
- // Locals have no relevance for collector
+ // Locals have no relevance for collector.
}
}
}
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::DropGlue(_, None) => {
- // don't need to emit shim if we are calling directly.
+ // Don't need to emit shim if we are calling directly.
if !is_direct_call {
output.push(create_fn_mono_item(instance));
}
}
}
-// Returns true if we should codegen an instance in the local crate.
-// Returns false if we can just link to the upstream crate and therefore don't
+// Returns `true` if we should codegen an instance in the local crate.
+// Returns `false` if we can just link to the upstream crate and therefore don't
// need a mono item.
fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
let def_id = match instance.def {
};
if tcx.is_foreign_item(def_id) {
- // We can always link to foreign items
+ // We can always link to foreign items.
return false;
}
if def_id.is_local() {
- // local items cannot be referred to locally without monomorphizing them locally
+ // Local items cannot be referred to locally without monomorphizing them locally.
return true;
}
if tcx.is_reachable_non_generic(def_id) ||
is_available_upstream_generic(tcx, def_id, instance.substs) {
// We can link to the item in question, no instance needed
- // in this crate
+ // in this crate.
return false;
}
if !tcx.is_mir_available(def_id) {
- bug!("Cannot create local mono-item for {:?}", def_id)
+ bug!("cannot create local mono-item for {:?}", def_id)
}
return true;
// If this instance has non-erasable parameters, it cannot be a shared
// monomorphization. Non-generic instances are already handled above
- // by `is_reachable_non_generic()`
+ // by `is_reachable_non_generic()`.
if substs.non_erasable_generics().next().is_none() {
return false
}
}
}
-/// For given pair of source and target type that occur in an unsizing coercion,
+/// For a given pair of source and target type that occur in an unsizing coercion,
/// this function finds the pair of types that determines the vtable linking
/// them.
///
source_fields.len() == target_fields.len());
find_vtable_types_for_unsizing(tcx,
- source_fields[coerce_index].ty(tcx,
- source_substs),
- target_fields[coerce_index].ty(tcx,
- target_substs))
+ source_fields[coerce_index].ty(tcx, source_substs),
+ target_fields[coerce_index].ty(tcx, target_substs)
+ )
}
_ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
source_ty,
output.extend(methods);
}
- // Also add the destructor
+ // Also add the destructor.
visit_drop_use(tcx, impl_ty, false, output);
}
}
fn visit_item(&mut self, item: &'v hir::Item) {
match item.kind {
hir::ItemKind::ExternCrate(..) |
- hir::ItemKind::Use(..) |
- hir::ItemKind::ForeignMod(..) |
- hir::ItemKind::TyAlias(..) |
- hir::ItemKind::Trait(..) |
- hir::ItemKind::TraitAlias(..) |
+ hir::ItemKind::Use(..) |
+ hir::ItemKind::ForeignMod(..) |
+ hir::ItemKind::TyAlias(..) |
+ hir::ItemKind::Trait(..) |
+ hir::ItemKind::TraitAlias(..) |
hir::ItemKind::OpaqueTy(..) |
- hir::ItemKind::Mod(..) => {
- // Nothing to do, just keep recursing...
+ hir::ItemKind::Mod(..) => {
+ // Nothing to do, just keep recursing.
}
hir::ItemKind::Impl(..) => {
let def_id = self.tcx.hir().local_def_id(ii.hir_id);
self.push_if_root(def_id);
}
- _ => { /* Nothing to do here */ }
+ _ => { /* nothing to do here */ }
}
}
}
}
}
- /// If `def_id` represents a root, then push it onto the list of
+ /// If `def_id` represents a root, pushes it onto the list of
/// outputs. (Note that all roots must be monomorphic.)
fn push_if_root(&mut self, def_id: DefId) {
if self.is_root(def_id) {
}
}
-/// Scan the miri alloc in order to find function calls, closures, and drop-glue
+/// Scans the miri alloc in order to find function calls, closures, and drop-glue.
fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<MonoItem<'tcx>>) {
let alloc_kind = tcx.alloc_map.lock().get(alloc_id);
match alloc_kind {
}
}
-/// Scan the MIR in order to find function calls, closures, and drop-glue
+/// Scans the MIR in order to find function calls, closures, and drop-glue.
fn collect_neighbours<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
}
vtable => {
- bug!("invalid CoerceUnsized vtable: {:?}", vtable);
+ bug!("invalid `CoerceUnsized` vtable: {:?}", vtable);
}
}
}
source_info,
visibility_scope: source_info.scope,
internal: false,
- is_user_variable: None,
+ local_info: LocalInfo::Other,
is_block_tail: None,
}
}
use rustc::mir::*;
use rustc::ty::{self, Ty};
+use rustc::hir::def_id::DefId;
use syntax_pos::DUMMY_SP;
use super::{ConstKind, Item as ConstCx};
/// of the type.
fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> bool;
- fn in_static(_cx: &ConstCx<'_, 'tcx>, _static: &Static<'tcx>) -> bool {
+ fn in_static(_cx: &ConstCx<'_, 'tcx>, _def_id: DefId) -> bool {
// FIXME(eddyb) should we do anything here for value properties?
false
}
projection: [],
} => per_local(*local),
PlaceRef {
- base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted(..),
- ..
- }),
+ base: PlaceBase::Static(_),
projection: [],
} => bug!("qualifying already promoted MIR"),
- PlaceRef {
- base: PlaceBase::Static(static_),
- projection: [],
- } => {
- Self::in_static(cx, static_)
- },
PlaceRef {
base: _,
projection: [.., _],
Operand::Move(ref place) => Self::in_place(cx, per_local, place.as_ref()),
Operand::Constant(ref constant) => {
- if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val {
+ if let Some(static_) = constant.check_static_ptr(cx.tcx) {
+ Self::in_static(cx, static_)
+ } else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val {
// Don't peek inside trait associated constants.
if cx.tcx.trait_of_item(def_id).is_some() {
Self::in_any_value_of_ty(cx, constant.literal.ty)
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
-use rustc::hir::HirId;
+use rustc::hir::{HirId, def_id::DefId};
use rustc::middle::lang_items;
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
use rustc::mir::*;
let span = self.span;
self.check_op_spanned(op, span)
}
+
+ fn check_static(&mut self, def_id: DefId, span: Span) -> CheckOpResult {
+ let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local);
+ if is_thread_local {
+ self.check_op_spanned(ops::ThreadLocalAccess, span)
+ } else {
+ self.check_op_spanned(ops::StaticAccess, span)
+ }
+ }
}
impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
match place_base {
PlaceBase::Local(_) => {}
- PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => {
+ PlaceBase::Static(_) => {
bug!("Promotion must be run after const validation");
}
+ }
+ }
- PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
- let is_thread_local = self.tcx.has_attr(*def_id, sym::thread_local);
- if is_thread_local {
- self.check_op(ops::ThreadLocalAccess);
- } else if self.const_kind() != ConstKind::Static || !context.is_mutating_use() {
- self.check_op(ops::StaticAccess);
- }
+ fn visit_operand(
+ &mut self,
+ op: &Operand<'tcx>,
+ location: Location,
+ ) {
+ self.super_operand(op, location);
+ if let Operand::Constant(c) = op {
+ if let Some(def_id) = c.check_static_ptr(self.tcx) {
+ self.check_static(def_id, self.span);
}
}
}
match elem {
ProjectionElem::Deref => {
- if context.is_mutating_use() {
- self.check_op(ops::MutDeref);
- }
-
let base_ty = Place::ty_from(place_base, proj_base, self.body, self.tcx).ty;
if let ty::RawPtr(_) = base_ty.kind {
+ if proj_base.is_empty() {
+ if let (PlaceBase::Local(local), []) = (place_base, proj_base) {
+ let decl = &self.body.local_decls[*local];
+ if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
+ let span = decl.source_info.span;
+ self.check_static(def_id, span);
+ return;
+ }
+ }
+ }
self.check_op(ops::RawPtrDeref);
}
+
+ if context.is_mutating_use() {
+ self.check_op(ops::MutDeref);
+ }
}
ProjectionElem::ConstantIndex {..} |
// Locals are safe.
}
PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
- bug!("unsafety checking should happen before promotion")
+ bug!("unsafety checking should happen before promotion");
}
- PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
- if self.tcx.is_mutable_static(def_id) {
- self.require_unsafe(
- "use of mutable static",
- "mutable statics can be mutated by multiple threads: aliasing \
- violations or data races will cause undefined behavior",
- UnsafetyViolationKind::General,
- );
- } else if self.tcx.is_foreign_item(def_id) {
- self.require_unsafe(
- "use of extern static",
- "extern statics are not controlled by the Rust type system: \
- invalid data, aliasing violations or data races will cause \
- undefined behavior",
- UnsafetyViolationKind::General,
- );
- }
+ PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
+ bug!("StaticKind::Static should not exist");
}
}
}
let old_source_info = self.source_info;
if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
- if self.body.local_decls[*local].internal {
+ let decl = &self.body.local_decls[*local];
+ if decl.internal {
// Internal locals are used in the `move_val_init` desugaring.
// We want to check unsafety against the source info of the
// desugaring, rather than the source info of the RHS.
self.source_info = self.body.local_decls[*local].source_info;
+ } else if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
+ if self.tcx.is_mutable_static(def_id) {
+ self.require_unsafe(
+ "use of mutable static",
+ "mutable statics can be mutated by multiple threads: aliasing \
+ violations or data races will cause undefined behavior",
+ UnsafetyViolationKind::General,
+ );
+ return;
+ } else if self.tcx.is_foreign_item(def_id) {
+ self.require_unsafe(
+ "use of extern static",
+ "extern statics are not controlled by the Rust type system: \
+ invalid data, aliasing violations or data races will cause \
+ undefined behavior",
+ UnsafetyViolationKind::General,
+ );
+ return;
+ }
}
}
let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
visibility_scope: source_info.scope,
internal: false,
is_block_tail: None,
- is_user_variable: None,
+ local_info: LocalInfo::Other
};
let new_ret_local = Local::new(body.local_decls.len());
body.local_decls.push(new_ret);
visibility_scope: source_info.scope,
internal: false,
is_block_tail: None,
- is_user_variable: None,
+ local_info: LocalInfo::Other
};
make_generator_state_argument_indirect(tcx, def_id, &mut body);
visibility_scope: source_info.scope,
internal: false,
is_block_tail: None,
- is_user_variable: None,
+ local_info: LocalInfo::Other
};
if tcx.sess.opts.debugging_opts.mir_emit_retag {
// Alias tracking must know we changed the type
pub mod check_consts;
pub mod check_unsafety;
pub mod simplify_branches;
+pub mod simplify_try;
pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
©_prop::CopyPropagation,
&simplify_branches::SimplifyBranches::new("after-copy-prop"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
+ &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"),
+ &simplify_try::SimplifyArmIdentity,
+ &simplify_try::SimplifyBranchSame,
&simplify::SimplifyCfg::new("final"),
&simplify::SimplifyLocals,
projection: [],
} => self.validate_local(*local),
PlaceRef {
- base: PlaceBase::Static(box Static {
- kind: StaticKind::Promoted { .. },
- ..
- }),
+ base: PlaceBase::Static(_),
projection: [],
} => bug!("qualifying already promoted MIR"),
- PlaceRef {
- base: PlaceBase::Static(box Static {
- kind: StaticKind::Static,
- def_id,
- ..
- }),
- projection: [],
- } => {
- // Only allow statics (not consts) to refer to other statics.
- // FIXME(eddyb) does this matter at all for promotion?
- let is_static = self.const_kind.map_or(false, |k| k.is_static());
- if !is_static {
- return Err(Unpromotable);
- }
-
- let is_thread_local = self.tcx.has_attr(*def_id, sym::thread_local);
- if is_thread_local {
- return Err(Unpromotable);
- }
-
- Ok(())
- }
PlaceRef {
base: _,
projection: [proj_base @ .., elem],
// The qualifs for a constant (e.g. `HasMutInterior`) are checked in
// `validate_rvalue` upon access.
- Operand::Constant(_) => Ok(()),
+ Operand::Constant(c) => {
+ if let Some(def_id) = c.check_static_ptr(self.tcx) {
+ // Only allow statics (not consts) to refer to other statics.
+ // FIXME(eddyb) does this matter at all for promotion?
+ let is_static = self.const_kind.map_or(false, |k| k.is_static());
+ if !is_static {
+ return Err(Unpromotable);
+ }
+
+ let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local);
+ if is_thread_local {
+ return Err(Unpromotable);
+ }
+ }
+
+ Ok(())
+ },
}
}
Operand::Move(place) | Operand::Copy(place) => {
check_place(tcx, place, span, def_id, body)
}
- Operand::Constant(_) => Ok(()),
+ Operand::Constant(c) => match c.check_static_ptr(tcx) {
+ Some(_) => Err((span, "cannot access `static` items in const fn".into())),
+ None => Ok(()),
+ },
}
}
}
}
- match place.base {
- PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
- Err((span, "cannot access `static` items in const fn".into()))
- }
- PlaceBase::Local(_)
- | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()),
- }
+ Ok(())
}
/// Returns whether `allow_internal_unstable(..., <feature_gate>, ...)` is present.
--- /dev/null
+//! The general point of the optimizations provided here is to simplify something like:
+//!
+//! ```rust
+//! match x {
+//! Ok(x) => Ok(x),
+//! Err(x) => Err(x)
+//! }
+//! ```
+//!
+//! into just `x`.
+
+use crate::transform::{MirPass, MirSource, simplify};
+use rustc::ty::{TyCtxt, Ty};
+use rustc::mir::*;
+use rustc_target::abi::VariantIdx;
+use itertools::Itertools as _;
+
+/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
+///
+/// This is done by transforming basic blocks where the statements match:
+///
+/// ```rust
+/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
+/// ((_LOCAL_0 as Variant).FIELD: TY) = move _LOCAL_TMP;
+/// discriminant(_LOCAL_0) = VAR_IDX;
+/// ```
+///
+/// into:
+///
+/// ```rust
+/// _LOCAL_0 = move _LOCAL_1
+/// ```
+pub struct SimplifyArmIdentity;
+
+impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
+ fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+ for bb in body.basic_blocks_mut() {
+ // Need 3 statements:
+ let (s0, s1, s2) = match &mut *bb.statements {
+ [s0, s1, s2] => (s0, s1, s2),
+ _ => continue,
+ };
+
+ // Pattern match on the form we want:
+ let (local_tmp_s0, local_1, vf_s0) = match match_get_variant_field(s0) {
+ None => continue,
+ Some(x) => x,
+ };
+ let (local_tmp_s1, local_0, vf_s1) = match match_set_variant_field(s1) {
+ None => continue,
+ Some(x) => x,
+ };
+ if local_tmp_s0 != local_tmp_s1
+ || vf_s0 != vf_s1
+ || Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
+ {
+ continue;
+ }
+
+ // Right shape; transform!
+ match &mut s0.kind {
+ StatementKind::Assign(box (place, rvalue)) => {
+ *place = local_0.into();
+ *rvalue = Rvalue::Use(Operand::Move(local_1.into()));
+ }
+ _ => unreachable!(),
+ }
+ s1.make_nop();
+ s2.make_nop();
+ }
+ }
+}
+
+/// Match on:
+/// ```rust
+/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
+/// ```
+fn match_get_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
+ match &stmt.kind {
+ StatementKind::Assign(box (place_into, rvalue_from)) => match rvalue_from {
+ Rvalue::Use(Operand::Copy(pf)) | Rvalue::Use(Operand::Move(pf)) => {
+ let local_into = place_into.as_local()?;
+ let (local_from, vf) = match_variant_field_place(&pf)?;
+ Some((local_into, local_from, vf))
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+}
+
+/// Match on:
+/// ```rust
+/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO;
+/// ```
+fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
+ match &stmt.kind {
+ StatementKind::Assign(box (place_from, rvalue_into)) => match rvalue_into {
+ Rvalue::Use(Operand::Move(place_into)) => {
+ let local_into = place_into.as_local()?;
+ let (local_from, vf) = match_variant_field_place(&place_from)?;
+ Some((local_into, local_from, vf))
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+}
+
+/// Match on:
+/// ```rust
+/// discriminant(_LOCAL_TO_SET) = VAR_IDX;
+/// ```
+fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> {
+ match &stmt.kind {
+ StatementKind::SetDiscriminant { place, variant_index } => Some((
+ place.as_local()?,
+ *variant_index
+ )),
+ _ => None,
+ }
+}
+
+#[derive(PartialEq)]
+struct VarField<'tcx> {
+ field: Field,
+ field_ty: Ty<'tcx>,
+ var_idx: VariantIdx,
+}
+
+/// Match on `((_LOCAL as Variant).FIELD: TY)`.
+fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
+ match place.as_ref() {
+ PlaceRef {
+ base: &PlaceBase::Local(local),
+ projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
+ } => Some((local, VarField { field, field_ty: ty, var_idx })),
+ _ => None,
+ }
+}
+
+/// Simplifies `SwitchInt(_) -> [targets]`,
+/// where all the `targets` have the same form,
+/// into `goto -> target_first`.
+pub struct SimplifyBranchSame;
+
+impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
+ fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+ let mut did_remove_blocks = false;
+ let bbs = body.basic_blocks_mut();
+ for bb_idx in bbs.indices() {
+ let targets = match &bbs[bb_idx].terminator().kind {
+ TerminatorKind::SwitchInt { targets, .. } => targets,
+ _ => continue,
+ };
+
+ let mut iter_bbs_reachable = targets
+ .iter()
+ .map(|idx| (*idx, &bbs[*idx]))
+ .filter(|(_, bb)| {
+ // Reaching `unreachable` is UB so assume it doesn't happen.
+ bb.terminator().kind != TerminatorKind::Unreachable
+ // But `asm!(...)` could abort the program,
+ // so we cannot assume that the `unreachable` terminator itself is reachable.
+ // FIXME(Centril): use a normalization pass instead of a check.
+ || bb.statements.iter().any(|stmt| match stmt.kind {
+ StatementKind::InlineAsm(..) => true,
+ _ => false,
+ })
+ })
+ .peekable();
+
+ // We want to `goto -> bb_first`.
+ let bb_first = iter_bbs_reachable
+ .peek()
+ .map(|(idx, _)| *idx)
+ .unwrap_or(targets[0]);
+
+ // All successor basic blocks should have the exact same form.
+ let all_successors_equivalent = iter_bbs_reachable
+ .map(|(_, bb)| bb)
+ .tuple_windows()
+ .all(|(bb_l, bb_r)| {
+ bb_l.is_cleanup == bb_r.is_cleanup
+ && bb_l.terminator().kind == bb_r.terminator().kind
+ && bb_l.statements.iter().eq_by(&bb_r.statements, |x, y| x.kind == y.kind)
+ });
+
+ if all_successors_equivalent {
+ // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`.
+ bbs[bb_idx].terminator_mut().kind = TerminatorKind::Goto { target: bb_first };
+ did_remove_blocks = true;
+ }
+ }
+
+ if did_remove_blocks {
+ // We have dead blocks now, so remove those.
+ simplify::remove_dead_blocks(body);
+ }
+ }
+}
--- /dev/null
+//! Process the potential `cfg` attributes on a module.
+//! Also determine if the module should be included in this configuration.
+//!
+//! This module properly belongs in syntax_expand, but for now it's tied into
+//! parsing, so we leave it here to avoid complicated out-of-line dependencies.
+//!
+//! A principled solution to this wrong location would be to implement [#64197].
+//!
+//! [#64197]: https://github.com/rust-lang/rust/issues/64197
+
+use crate::validate_attr;
+use syntax::attr::HasAttrs;
+use syntax::feature_gate::{
+ feature_err,
+ EXPLAIN_STMT_ATTR_SYNTAX,
+ Features,
+ get_features,
+ GateIssue,
+};
+use syntax::attr;
+use syntax::ast;
+use syntax::edition::Edition;
+use syntax::mut_visit::*;
+use syntax::ptr::P;
+use syntax::sess::ParseSess;
+use syntax::util::map_in_place::MapInPlace;
+use syntax_pos::symbol::sym;
+
+use errors::Applicability;
+use smallvec::SmallVec;
+
+/// A folder that strips out items that do not belong in the current configuration.
+pub struct StripUnconfigured<'a> {
+ pub sess: &'a ParseSess,
+ pub features: Option<&'a Features>,
+}
+
+// `cfg_attr`-process the crate's attributes and compute the crate's features.
+pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition,
+ allow_features: &Option<Vec<String>>) -> (ast::Crate, Features) {
+ let features;
+ {
+ let mut strip_unconfigured = StripUnconfigured {
+ sess,
+ features: None,
+ };
+
+ let unconfigured_attrs = krate.attrs.clone();
+ let err_count = sess.span_diagnostic.err_count();
+ if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
+ krate.attrs = attrs;
+ } else { // the entire crate is unconfigured
+ krate.attrs = Vec::new();
+ krate.module.items = Vec::new();
+ return (krate, Features::new());
+ }
+
+ features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);
+
+ // Avoid reconfiguring malformed `cfg_attr`s
+ if err_count == sess.span_diagnostic.err_count() {
+ strip_unconfigured.features = Some(&features);
+ strip_unconfigured.configure(unconfigured_attrs);
+ }
+ }
+
+ (krate, features)
+}
+
+#[macro_export]
+macro_rules! configure {
+ ($this:ident, $node:ident) => {
+ match $this.configure($node) {
+ Some(node) => node,
+ None => return Default::default(),
+ }
+ }
+}
+
+impl<'a> StripUnconfigured<'a> {
+ pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
+ self.process_cfg_attrs(&mut node);
+ if self.in_cfg(node.attrs()) { Some(node) } else { None }
+ }
+
+ /// Parse and expand all `cfg_attr` attributes into a list of attributes
+ /// that are within each `cfg_attr` that has a true configuration predicate.
+ ///
+ /// Gives compiler warnigns if any `cfg_attr` does not contain any
+ /// attributes and is in the original source code. Gives compiler errors if
+ /// the syntax of any `cfg_attr` is incorrect.
+ pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: &mut T) {
+ node.visit_attrs(|attrs| {
+ attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
+ });
+ }
+
+ /// Parse and expand a single `cfg_attr` attribute into a list of attributes
+ /// when the configuration predicate is true, or otherwise expand into an
+ /// empty list of attributes.
+ ///
+ /// Gives a compiler warning when the `cfg_attr` contains no attributes and
+ /// is in the original source file. Gives a compiler error if the syntax of
+ /// the attribute is incorrect.
+ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
+ if !attr.has_name(sym::cfg_attr) {
+ return vec![attr];
+ }
+ if attr.get_normal_item().tokens.is_empty() {
+ self.sess.span_diagnostic
+ .struct_span_err(
+ attr.span,
+ "malformed `cfg_attr` attribute input",
+ ).span_suggestion(
+ attr.span,
+ "missing condition and attribute",
+ "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(),
+ Applicability::HasPlaceholders,
+ ).note("for more information, visit \
+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
+ #the-cfg_attr-attribute>")
+ .emit();
+ return vec![];
+ }
+
+ let res = crate::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr());
+ let (cfg_predicate, expanded_attrs) = match res {
+ Ok(result) => result,
+ Err(mut e) => {
+ e.emit();
+ return vec![];
+ }
+ };
+
+ // Lint on zero attributes in source.
+ if expanded_attrs.is_empty() {
+ return vec![attr];
+ }
+
+ // At this point we know the attribute is considered used.
+ attr::mark_used(&attr);
+
+ if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+ // We call `process_cfg_attr` recursively in case there's a
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+ expanded_attrs.into_iter()
+ .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item(
+ attr.style,
+ item,
+ span,
+ )))
+ .collect()
+ } else {
+ vec![]
+ }
+ }
+
+ /// Determines if a node with the given attributes should be included in this configuration.
+ pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool {
+ attrs.iter().all(|attr| {
+ if !is_cfg(attr) {
+ return true;
+ }
+
+ let error = |span, msg, suggestion: &str| {
+ let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
+ if !suggestion.is_empty() {
+ err.span_suggestion(
+ span,
+ "expected syntax is",
+ suggestion.into(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
+ true
+ };
+
+ let meta_item = match validate_attr::parse_meta(self.sess, attr) {
+ Ok(meta_item) => meta_item,
+ Err(mut err) => { err.emit(); return true; }
+ };
+ let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() {
+ nested_meta_items
+ } else {
+ return error(meta_item.span, "`cfg` is not followed by parentheses",
+ "cfg(/* predicate */)");
+ };
+
+ if nested_meta_items.is_empty() {
+ return error(meta_item.span, "`cfg` predicate is not specified", "");
+ } else if nested_meta_items.len() > 1 {
+ return error(nested_meta_items.last().unwrap().span(),
+ "multiple `cfg` predicates are specified", "");
+ }
+
+ match nested_meta_items[0].meta_item() {
+ Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
+ None => error(nested_meta_items[0].span(),
+ "`cfg` predicate key cannot be a literal", ""),
+ }
+ })
+ }
+
+ /// Visit attributes on expression and statements (but not attributes on items in blocks).
+ fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
+ // flag the offending attributes
+ for attr in attrs.iter() {
+ self.maybe_emit_expr_attr_err(attr);
+ }
+ }
+
+ /// If attributes are not allowed on expressions, emit an error for `attr`
+ pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) {
+ if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
+ let mut err = feature_err(self.sess,
+ sym::stmt_expr_attributes,
+ attr.span,
+ GateIssue::Language,
+ EXPLAIN_STMT_ATTR_SYNTAX);
+
+ if attr.is_doc_comment() {
+ err.help("`///` is for documentation comments. For a plain comment, use `//`.");
+ }
+
+ err.emit();
+ }
+ }
+
+ pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
+ let ast::ForeignMod { abi: _, items } = foreign_mod;
+ items.flat_map_in_place(|item| self.configure(item));
+ }
+
+ pub fn configure_generic_params(&mut self, params: &mut Vec<ast::GenericParam>) {
+ params.flat_map_in_place(|param| self.configure(param));
+ }
+
+ fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
+ match vdata {
+ ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) =>
+ fields.flat_map_in_place(|field| self.configure(field)),
+ ast::VariantData::Unit(_) => {}
+ }
+ }
+
+ pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) {
+ match item {
+ ast::ItemKind::Struct(def, _generics) |
+ ast::ItemKind::Union(def, _generics) => self.configure_variant_data(def),
+ ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => {
+ variants.flat_map_in_place(|variant| self.configure(variant));
+ for variant in variants {
+ self.configure_variant_data(&mut variant.data);
+ }
+ }
+ _ => {}
+ }
+ }
+
+ pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) {
+ match expr_kind {
+ ast::ExprKind::Match(_m, arms) => {
+ arms.flat_map_in_place(|arm| self.configure(arm));
+ }
+ ast::ExprKind::Struct(_path, fields, _base) => {
+ fields.flat_map_in_place(|field| self.configure(field));
+ }
+ _ => {}
+ }
+ }
+
+ pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
+ self.visit_expr_attrs(expr.attrs());
+
+ // If an expr is valid to cfg away it will have been removed by the
+ // outer stmt or expression folder before descending in here.
+ // Anything else is always required, and thus has to error out
+ // in case of a cfg attr.
+ //
+ // N.B., this is intentionally not part of the visit_expr() function
+ // in order for filter_map_expr() to be able to avoid this check
+ if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
+ let msg = "removing an expression is not supported in this position";
+ self.sess.span_diagnostic.span_err(attr.span, msg);
+ }
+
+ self.process_cfg_attrs(expr)
+ }
+
+ pub fn configure_pat(&mut self, pat: &mut P<ast::Pat>) {
+ if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind {
+ fields.flat_map_in_place(|field| self.configure(field));
+ }
+ }
+
+ pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) {
+ fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg));
+ }
+}
+
+impl<'a> MutVisitor for StripUnconfigured<'a> {
+ fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
+ self.configure_foreign_mod(foreign_mod);
+ noop_visit_foreign_mod(foreign_mod, self);
+ }
+
+ fn visit_item_kind(&mut self, item: &mut ast::ItemKind) {
+ self.configure_item_kind(item);
+ noop_visit_item_kind(item, self);
+ }
+
+ fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
+ self.configure_expr(expr);
+ self.configure_expr_kind(&mut expr.kind);
+ noop_visit_expr(expr, self);
+ }
+
+ fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+ let mut expr = configure!(self, expr);
+ self.configure_expr_kind(&mut expr.kind);
+ noop_visit_expr(&mut expr, self);
+ Some(expr)
+ }
+
+ fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+ noop_flat_map_stmt(configure!(self, stmt), self)
+ }
+
+ fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+ noop_flat_map_item(configure!(self, item), self)
+ }
+
+ fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+ noop_flat_map_impl_item(configure!(self, item), self)
+ }
+
+ fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+ noop_flat_map_trait_item(configure!(self, item), self)
+ }
+
+ fn visit_mac(&mut self, _mac: &mut ast::Mac) {
+ // Don't configure interpolated AST (cf. issue #34171).
+ // Interpolated AST will get configured once the surrounding tokens are parsed.
+ }
+
+ fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
+ self.configure_pat(pat);
+ noop_visit_pat(pat, self)
+ }
+
+ fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) {
+ self.configure_fn_decl(&mut fn_decl);
+ noop_visit_fn_decl(fn_decl, self);
+ }
+}
+
+fn is_cfg(attr: &ast::Attribute) -> bool {
+ attr.check_name(sym::cfg)
+}
+
+/// Process the potential `cfg` attributes on a module.
+/// Also determine if the module should be included in this configuration.
+pub fn process_configure_mod(
+ sess: &ParseSess,
+ cfg_mods: bool,
+ attrs: &[ast::Attribute],
+) -> (bool, Vec<ast::Attribute>) {
+ // Don't perform gated feature checking.
+ let mut strip_unconfigured = StripUnconfigured { sess, features: None };
+ let mut attrs = attrs.to_owned();
+ strip_unconfigured.process_cfg_attrs(&mut attrs);
+ (!cfg_mods || strip_unconfigured.in_cfg(&attrs), attrs)
+}
use parser::{Parser, emit_unclosed_delims, make_unclosed_delims_error};
pub mod lexer;
pub mod validate_attr;
+#[macro_use]
+pub mod config;
#[derive(Clone)]
pub struct Directory<'a> {
}
}
- /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
- pub(super) fn eat_bad_pub(&mut self) {
- // When `unclosed_delims` is populated, it means that the code being parsed is already
- // quite malformed, which might mean that, for example, a pub struct definition could be
- // parsed as being a trait item, which is invalid and this error would trigger
- // unconditionally, resulting in misleading diagnostics. Because of this, we only attempt
- // this nice to have recovery for code that is otherwise well formed.
- if self.token.is_keyword(kw::Pub) && self.unclosed_delims.is_empty() {
- match self.parse_visibility(false) {
- Ok(vis) => {
- self.diagnostic()
- .struct_span_err(vis.span, "unnecessary visibility qualifier")
- .span_label(vis.span, "`pub` not permitted here")
- .emit();
- }
- Err(mut err) => err.emit(),
- }
- }
- }
-
/// Eats tokens until we can be relatively sure we reached the end of the
/// statement. This is something of a best-effort heuristic.
///
-use super::{Parser, PathStyle};
+use super::{Parser, PathStyle, FollowedByType};
use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim};
use crate::maybe_whole;
let lo = self.token.span;
- let vis = self.parse_visibility(false)?;
+ let vis = self.parse_visibility(FollowedByType::No)?;
if self.eat_keyword(kw::Use) {
// USE ITEM
mut attrs: Vec<Attribute>,
) -> PResult<'a, ImplItem> {
let lo = self.token.span;
- let vis = self.parse_visibility(false)?;
+ let vis = self.parse_visibility(FollowedByType::No)?;
let defaultness = self.parse_defaultness();
let (name, kind, generics) = if self.eat_keyword(kw::Type) {
let (name, ty, generics) = self.parse_type_alias()?;
mut attrs: Vec<Attribute>,
) -> PResult<'a, TraitItem> {
let lo = self.token.span;
- self.eat_bad_pub();
+ let vis = self.parse_visibility(FollowedByType::No)?;
let (name, kind, generics) = if self.eat_keyword(kw::Type) {
self.parse_trait_item_assoc_ty()?
} else if self.is_const_item() {
id: DUMMY_NODE_ID,
ident: name,
attrs,
+ vis,
generics,
kind,
span: lo.to(self.prev_span),
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
- let visibility = self.parse_visibility(false)?;
+ let visibility = self.parse_visibility(FollowedByType::No)?;
// FOREIGN STATIC ITEM
// Treat `const` as `static` for error recovery, but don't add it to expected tokens.
let variant_attrs = self.parse_outer_attributes()?;
let vlo = self.token.span;
- self.eat_bad_pub();
+ let vis = self.parse_visibility(FollowedByType::No)?;
let ident = self.parse_ident()?;
let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
let vr = ast::Variant {
ident,
+ vis,
id: DUMMY_NODE_ID,
attrs: variant_attrs,
data: struct_def,
self.parse_paren_comma_seq(|p| {
let attrs = p.parse_outer_attributes()?;
let lo = p.token.span;
- let vis = p.parse_visibility(true)?;
+ let vis = p.parse_visibility(FollowedByType::Yes)?;
let ty = p.parse_ty()?;
Ok(StructField {
span: lo.to(ty.span),
fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
- let vis = self.parse_visibility(false)?;
+ let vis = self.parse_visibility(FollowedByType::No)?;
self.parse_single_struct_field(lo, vis, attrs)
}
}
}
+pub enum FollowedByType { Yes, No }
+
impl<'a> Parser<'a> {
pub fn new(
sess: &'a ParseSess,
/// If the following element can't be a tuple (i.e., it's a function definition), then
/// it's not a tuple struct field), and the contents within the parentheses isn't valid,
/// so emit a proper diagnostic.
- pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
+ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
maybe_whole!(self, NtVis, |x| x);
self.expected_tokens.push(TokenType::Keyword(kw::Crate));
id: ast::DUMMY_NODE_ID,
};
return Ok(respan(lo.to(self.prev_span), vis));
- } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct.
+ } else if let FollowedByType::No = fbt {
+ // Provide this diagnostic if a type cannot follow;
+ // in particular, if this is not a tuple struct.
self.recover_incorrect_vis_restriction()?;
// Emit diagnostic, but continue with public visibility.
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
pub(super) fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> {
- // HACK(Centril): See documentation on `ParseSess::process_cfg_mod`.
- let (in_cfg, outer_attrs) = (self.sess.process_cfg_mod)(
+ let (in_cfg, outer_attrs) = crate::config::process_configure_mod(
self.sess,
self.cfg_mods,
outer_attrs,
}
ItemKind::Enum(ref def, _) => {
for variant in &def.variants {
+ self.invalid_visibility(&variant.vis, None);
for field in variant.data.fields() {
self.invalid_visibility(&field.vis, None);
}
}
visit::walk_impl_item(self, ii);
}
+
+ fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+ self.invalid_visibility(&ti.vis, None);
+ visit::walk_trait_item(self, ti);
+ }
}
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {
/// Denotes whether the context for the set of already bound bindings is a `Product`
/// or `Or` context. This is used in e.g., `fresh_binding` and `resolve_pattern_inner`.
/// See those functions for more information.
+#[derive(PartialEq)]
enum PatBoundCtx {
/// A product pattern context, e.g., `Variant(a, b)`.
Product,
// later passes make about or-patterns.)
let ident = ident.modern_and_legacy();
- // Walk outwards the stack of products / or-patterns and
- // find out if the identifier has been bound in any of these.
- let mut already_bound_and = false;
- let mut already_bound_or = false;
- for (is_sum, set) in bindings.iter_mut().rev() {
- match (is_sum, set.get(&ident).cloned()) {
- // Already bound in a product pattern, e.g. `(a, a)` which is not allowed.
- (PatBoundCtx::Product, Some(..)) => already_bound_and = true,
- // Already bound in an or-pattern, e.g. `V1(a) | V2(a)`.
- // This is *required* for consistency which is checked later.
- (PatBoundCtx::Or, Some(..)) => already_bound_or = true,
- // Not already bound here.
- _ => {}
- }
- }
+ let mut bound_iter = bindings.iter().filter(|(_, set)| set.contains(&ident));
+ // Already bound in a product pattern? e.g. `(a, a)` which is not allowed.
+ let already_bound_and = bound_iter.clone().any(|(ctx, _)| *ctx == PatBoundCtx::Product);
+ // Already bound in an or-pattern? e.g. `V1(a) | V2(a)`.
+ // This is *required* for consistency which is checked later.
+ let already_bound_or = bound_iter.any(|(ctx, _)| *ctx == PatBoundCtx::Or);
if already_bound_and {
// Overlap in a product pattern somewhere; report an error.
bitflags = "1.2.1"
log = "0.4"
rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_macros = { path = "../librustc_macros" }
rustc_serialize = { path = "../libserialize", package = "serialize" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_index = { path = "../librustc_index" }
use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
use rustc_index::vec::{Idx, IndexVec};
+use rustc_macros::HashStable_Generic;
use syntax_pos::Span;
pub mod call;
/// Size of a type in bytes.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(HashStable_Generic)]
pub struct Size {
raw: u64
}
/// Alignment of a type in bytes (always a power of two).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(HashStable_Generic)]
pub struct Align {
pow2: u8,
}
/// A pair of aligments, ABI-mandated and preferred.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(HashStable_Generic)]
pub struct AbiAndPrefAlign {
pub abi: Align,
pub pref: Align,
}
/// Integers, also used for enum discriminants.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, HashStable_Generic)]
pub enum Integer {
I8,
I16,
}
/// Fundamental unit of memory access and layout.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum Primitive {
/// The `bool` is the signedness of the `Integer` type.
///
/// Information about one scalar component of a Rust type.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(HashStable_Generic)]
pub struct Scalar {
pub value: Primitive,
}
/// Describes how the fields of a type are located in memory.
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum FieldPlacement {
/// All fields start at no offset. The `usize` is the field count.
///
/// Describes how values of the type are passed by target ABIs,
/// in terms of categories of C types there are ABI rules for.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum Abi {
Uninhabited,
Scalar(Scalar),
}
rustc_index::newtype_index! {
- pub struct VariantIdx { .. }
+ pub struct VariantIdx {
+ derive [HashStable_Generic]
+ }
}
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum Variants {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single {
},
}
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum DiscriminantKind {
/// Integer tag holding the discriminant value itself.
Tag,
},
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct Niche {
pub offset: Size,
pub scalar: Scalar,
}
}
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct LayoutDetails {
pub variants: Variants,
pub fields: FieldPlacement,
use std::fmt;
+use rustc_macros::HashStable_Generic;
+
#[cfg(test)]
mod tests;
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable,
+ Clone, Copy, Debug, HashStable_Generic)]
pub enum Abi {
// N.B., this ordering MUST match the AbiDatas array below.
// (This is ensured by the test indices_are_correct().)
use std::str::FromStr;
use crate::spec::abi::{Abi, lookup as lookup_abi};
+use rustc_macros::HashStable_Generic;
+
pub mod abi;
mod android_base;
mod apple_base;
((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
}
-#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum PanicStrategy {
Unwind,
Abort,
}
}
- pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat) -> bool {
+ pub fn check_dereferenceable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat) -> bool {
if let PatKind::Binding(..) = inner.kind {
if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) {
if let ty::Dynamic(..) = mt.ty.kind {
discrim_span: Option<Span>,
) -> Ty<'tcx> {
let tcx = self.tcx;
- let (box_ty, inner_ty) = if self.check_dereferencable(span, expected, &inner) {
+ let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) {
// Here, `demand::subtype` is good enough, but I don't
// think any errors can be introduced by using `demand::eqtype`.
let inner_ty = self.next_ty_var(TypeVariableOrigin {
) -> Ty<'tcx> {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
- let (rptr_ty, inner_ty) = if self.check_dereferencable(pat.span, expected, &inner) {
+ let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, &inner) {
// `demand::subtype` would be good enough, but using `eqtype` turns
// out to be equally general. See (note_1) for details.
// substitutions.
use crate::check::FnCtxt;
+
use rustc::hir;
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::DefIdSet;
use rustc_data_structures::sync::Lrc;
-use std::mem;
use syntax::symbol::sym;
use syntax_pos::Span;
+use std::mem;
+
///////////////////////////////////////////////////////////////////////////
// Entry point
if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.kind {
if let hir::OpaqueTyOrigin::TypeAlias = opaque_defn.origin {
if def_id == defin_ty_def_id {
- debug!("Skipping adding concrete definition for opaque type {:?} {:?}",
- opaque_defn, defin_ty_def_id);
+ debug!(
+ "skipping adding concrete definition for opaque type {:?} {:?}",
+ opaque_defn, defin_ty_def_id
+ );
skip_add = true;
}
}
if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
span_bug!(
span,
- "visit_opaque_types tried to write different types for the same \
- opaque type: {:?}, {:?}, {:?}, {:?}",
+ "`visit_opaque_types` tried to write different types for the same \
+ opaque type: {:?}, {:?}, {:?}, {:?}",
def_id,
definition_ty,
opaque_defn,
use syntax::sess::ParseSess;
use syntax::source_map::SourceMap;
use syntax::symbol::{kw, sym};
-use syntax_expand::config::process_configure_mod;
use syntax_pos::{Span, FileName};
/// Highlights `src`, returning the HTML output.
class, tooltip).unwrap();
}
- let sess = ParseSess::with_silent_emitter(process_configure_mod);
+ let sess = ParseSess::with_silent_emitter();
let fm = sess.source_map().new_source_file(
FileName::Custom(String::from("rustdoc-highlighting")),
src.to_owned(),
use syntax::token;
use syntax::sess::ParseSess;
use syntax::source_map::FilePathMapping;
-use syntax_expand::config::process_configure_mod;
use syntax_pos::{InnerSpan, FileName};
use crate::clean;
impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
- let sess = ParseSess::new(FilePathMapping::empty(), process_configure_mod);
+ let sess = ParseSess::new(FilePathMapping::empty());
let source_file = sess.source_map().new_source_file(
FileName::Custom(String::from("doctest")),
dox[code_block.code].to_owned(),
use std::process::{self, Command, Stdio};
use std::str;
use syntax::symbol::sym;
-use syntax_expand::config::process_configure_mod;
use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName};
use tempfile::Builder as TempFileBuilder;
use testing;
let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
let handler = Handler::with_emitter(false, None, box emitter);
- let sess = ParseSess::with_span_handler(handler, cm, process_configure_mod);
+ let sess = ParseSess::with_span_handler(handler, cm);
let mut found_main = false;
let mut found_extern_crate = cratename.is_none();
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_index = { path = "../librustc_index" }
rustc_lexer = { path = "../librustc_lexer" }
+rustc_macros = { path = "../librustc_macros" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_error_codes = { path = "../librustc_error_codes" }
use rustc_data_structures::thin_vec::ThinVec;
use rustc_index::vec::Idx;
use rustc_serialize::{self, Decoder, Encoder};
+use rustc_macros::HashStable_Generic;
use std::fmt;
Mac(Mac),
}
-#[derive(
- Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug, Copy,
-)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
+ RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
pub enum Mutability {
Mutable,
Immutable,
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Field {
+ pub attrs: ThinVec<Attribute>,
+ pub id: NodeId,
+ pub span: Span,
pub ident: Ident,
pub expr: P<Expr>,
- pub span: Span,
pub is_shorthand: bool,
- pub attrs: ThinVec<Attribute>,
- pub id: NodeId,
pub is_placeholder: bool,
}
}
/// A capture clause used in closures and `async` blocks.
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum CaptureBy {
/// `move |x| y + x`.
Value,
/// The movability of a generator / closure literal:
/// whether a generator contains self-references, causing it to be `!Unpin`.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
- RustcEncodable, RustcDecodable, Debug, Copy)]
+ RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
pub enum Movability {
/// May contain self-references, `!Unpin`.
Static,
}
// Clippy uses Hash and PartialEq
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq, HashStable_Generic)]
pub enum StrStyle {
/// A regular string, like `"foo"`.
Cooked,
// Clippy uses Hash and PartialEq
/// Type of the integer literal based on provided suffix.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)]
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq, HashStable_Generic)]
pub enum LitIntType {
/// e.g. `42_i32`.
Signed(IntTy),
}
/// Type of the float literal based on provided suffix.
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)]
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq, HashStable_Generic)]
pub enum LitFloatType {
/// A float literal with a suffix (`1f32` or `1E10f32`).
Suffixed(FloatTy),
///
/// E.g., `"foo"`, `42`, `12.34`, or `bool`.
// Clippy uses Hash and PartialEq
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq, HashStable_Generic)]
pub enum LitKind {
/// A string literal (`"foo"`).
Str(Symbol, StrStyle),
/// signature) or provided (meaning it has a default implementation).
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct TraitItem {
+ pub attrs: Vec<Attribute>,
pub id: NodeId,
+ pub span: Span,
+ pub vis: Visibility,
pub ident: Ident,
- pub attrs: Vec<Attribute>,
+
pub generics: Generics,
pub kind: TraitItemKind,
- pub span: Span,
/// See `Item::tokens` for what this is.
pub tokens: Option<TokenStream>,
}
/// Represents anything within an `impl` block.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct ImplItem {
+ pub attrs: Vec<Attribute>,
pub id: NodeId,
- pub ident: Ident,
+ pub span: Span,
pub vis: Visibility,
+ pub ident: Ident,
+
pub defaultness: Defaultness,
- pub attrs: Vec<Attribute>,
pub generics: Generics,
pub kind: ImplItemKind,
- pub span: Span,
/// See `Item::tokens` for what this is.
pub tokens: Option<TokenStream>,
}
Macro(Mac),
}
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic,
+ RustcEncodable, RustcDecodable, Debug)]
pub enum FloatTy {
F32,
F64,
}
}
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic,
+ RustcEncodable, RustcDecodable, Debug)]
pub enum IntTy {
Isize,
I8,
}
}
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy, Debug)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic,
+ RustcEncodable, RustcDecodable, Copy, Debug)]
pub enum UintTy {
Usize,
U8,
/// Inline assembly dialect.
///
/// E.g., `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
pub enum AsmDialect {
Att,
Intel,
}
/// Is the trait definition an auto trait?
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum IsAuto {
Yes,
No,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
- RustcEncodable, RustcDecodable, Debug)]
+ RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum Unsafety {
Unsafe,
Normal,
}
}
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum Constness {
Const,
NotConst,
/// Item defaultness.
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum Defaultness {
Default,
Final,
}
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum ImplPolarity {
/// `impl Trait for Type`
Positive,
pub struct EnumDef {
pub variants: Vec<Variant>,
}
-
/// Enum variant.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Variant {
- /// Name of the variant.
- pub ident: Ident,
/// Attributes of the variant.
pub attrs: Vec<Attribute>,
/// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
pub id: NodeId,
+ /// Span
+ pub span: Span,
+ /// The visibility of the variant. Syntactically accepted but not semantically.
+ pub vis: Visibility,
+ /// Name of the variant.
+ pub ident: Ident,
+
/// Fields and constructor id of the variant.
pub data: VariantData,
/// Explicit discriminant, e.g., `Foo = 1`.
pub disr_expr: Option<AnonConst>,
- /// Span
- pub span: Span,
/// Is a macro placeholder
pub is_placeholder: bool,
}
/// Distinguishes between `Attribute`s that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)]
pub enum AttrStyle {
Outer,
Inner,
}
}
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum CrateSugar {
/// Source is `pub(crate)`.
PubCrate,
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct StructField {
+ pub attrs: Vec<Attribute>,
+ pub id: NodeId,
pub span: Span,
- pub ident: Option<Ident>,
pub vis: Visibility,
- pub id: NodeId,
+ pub ident: Option<Ident>,
+
pub ty: P<Ty>,
- pub attrs: Vec<Attribute>,
pub is_placeholder: bool,
}
/// The name might be a dummy name in case of anonymous items.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Item {
- pub ident: Ident,
pub attrs: Vec<Attribute>,
pub id: NodeId,
- pub kind: ItemKind,
- pub vis: Visibility,
pub span: Span,
+ pub vis: Visibility,
+ pub ident: Ident,
+
+ pub kind: ItemKind,
/// Original tokens this item was parsed from. This isn't necessarily
/// available for all items, although over time more and more items should
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct ForeignItem {
- pub ident: Ident,
pub attrs: Vec<Attribute>,
- pub kind: ForeignItemKind,
pub id: NodeId,
pub span: Span,
pub vis: Visibility,
+ pub ident: Ident,
+
+ pub kind: ForeignItemKind,
}
/// An item within an `extern` block.
use std::num::NonZeroU32;
use syntax_pos::hygiene::Transparency;
use syntax_pos::{symbol::Symbol, symbol::sym, Span};
+use rustc_macros::HashStable_Generic;
use super::{mark_used, MetaItemKind};
}
/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
-#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug,
+ PartialEq, Eq, Hash, HashStable_Generic)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: Symbol,
}
/// The available stability levels.
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd,
+ Copy, Clone, Debug, Eq, Hash, HashStable_Generic)]
pub enum StabilityLevel {
// Reason for the current stability level and the relevant rust-lang issue
Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
}
}
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd,
+ Copy, Clone, Debug, Eq, Hash, HashStable_Generic)]
pub struct RustcDeprecation {
pub since: Symbol,
pub reason: Symbol,
}
}
-#[derive(RustcEncodable, RustcDecodable, Clone)]
+#[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)]
pub struct Deprecation {
pub since: Option<Symbol>,
pub note: Option<Symbol>,
ReprAlign(u32),
}
-#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
+#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone, HashStable_Generic)]
pub enum IntType {
SignedInt(ast::IntTy),
UnsignedInt(ast::UintTy)
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
}
-pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, vis: &mut T)
+pub fn noop_flat_map_variant<T: MutVisitor>(mut variant: Variant, visitor: &mut T)
-> SmallVec<[Variant; 1]>
{
- let Variant { ident, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
- vis.visit_ident(ident);
- visit_attrs(attrs, vis);
- vis.visit_id(id);
- vis.visit_variant_data(data);
- visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr));
- vis.visit_span(span);
+ let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
+ visitor.visit_ident(ident);
+ visitor.visit_vis(vis);
+ visit_attrs(attrs, visitor);
+ visitor.visit_id(id);
+ visitor.visit_variant_data(data);
+ visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
+ visitor.visit_span(span);
smallvec![variant]
}
}
}
-pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, vis: &mut T)
+pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, visitor: &mut T)
-> SmallVec<[TraitItem; 1]>
{
- let TraitItem { id, ident, attrs, generics, kind, span, tokens: _ } = &mut item;
- vis.visit_id(id);
- vis.visit_ident(ident);
- visit_attrs(attrs, vis);
- vis.visit_generics(generics);
+ let TraitItem { id, ident, vis, attrs, generics, kind, span, tokens: _ } = &mut item;
+ visitor.visit_id(id);
+ visitor.visit_ident(ident);
+ visitor.visit_vis(vis);
+ visit_attrs(attrs, visitor);
+ visitor.visit_generics(generics);
match kind {
TraitItemKind::Const(ty, default) => {
- vis.visit_ty(ty);
- visit_opt(default, |default| vis.visit_expr(default));
+ visitor.visit_ty(ty);
+ visit_opt(default, |default| visitor.visit_expr(default));
}
TraitItemKind::Method(sig, body) => {
- visit_fn_sig(sig, vis);
- visit_opt(body, |body| vis.visit_block(body));
+ visit_fn_sig(sig, visitor);
+ visit_opt(body, |body| visitor.visit_block(body));
}
TraitItemKind::Type(bounds, default) => {
- visit_bounds(bounds, vis);
- visit_opt(default, |default| vis.visit_ty(default));
+ visit_bounds(bounds, visitor);
+ visit_opt(default, |default| visitor.visit_ty(default));
}
TraitItemKind::Macro(mac) => {
- vis.visit_mac(mac);
+ visitor.visit_mac(mac);
}
}
- vis.visit_span(span);
+ visitor.visit_span(span);
smallvec![item]
}
let var = ast::Variant {
ident,
+ vis: source_map::respan(syntax_pos::DUMMY_SP, ast::VisibilityKind::Inherited),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
//! It also serves as an input to the parser itself.
-use crate::ast::{CrateConfig, NodeId, Attribute};
+use crate::ast::{CrateConfig, NodeId};
use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
use crate::source_map::{SourceMap, FilePathMapping};
use crate::feature_gate::UnstableFeatures;
pub gated_spans: GatedSpans,
/// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
pub reached_eof: Lock<bool>,
- /// Process the potential `cfg` attributes on a module.
- /// Also determine if the module should be included in this configuration.
- ///
- /// HACK(Centril): This is used to break a cyclic dependency between
- /// the parser and cfg-stripping as defined in `syntax_expand::config`.
- /// The dependency edge from the parser comes from `parse_item_mod`.
- /// A principled solution to this hack would be to implement [#64197].
- ///
- /// [#64197]: https://github.com/rust-lang/rust/issues/64197
- pub process_cfg_mod: ProcessCfgMod,
}
-pub type ProcessCfgMod = fn(&ParseSess, bool, &[Attribute]) -> (bool, Vec<Attribute>);
-
impl ParseSess {
- pub fn new(file_path_mapping: FilePathMapping, process_cfg_mod: ProcessCfgMod) -> Self {
+ pub fn new(file_path_mapping: FilePathMapping) -> Self {
let cm = Lrc::new(SourceMap::new(file_path_mapping));
let handler = Handler::with_tty_emitter(
ColorConfig::Auto,
None,
Some(cm.clone()),
);
- ParseSess::with_span_handler(handler, cm, process_cfg_mod)
+ ParseSess::with_span_handler(handler, cm)
}
pub fn with_span_handler(
handler: Handler,
source_map: Lrc<SourceMap>,
- process_cfg_mod: ProcessCfgMod,
) -> Self {
Self {
span_diagnostic: handler,
- process_cfg_mod,
unstable_features: UnstableFeatures::from_environment(),
config: FxHashSet::default(),
edition: ExpnId::root().expn_data().edition,
}
}
- pub fn with_silent_emitter(process_cfg_mod: ProcessCfgMod) -> Self {
+ pub fn with_silent_emitter() -> Self {
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
- ParseSess::with_span_handler(handler, cm, process_cfg_mod)
+ ParseSess::with_span_handler(handler, cm)
}
#[inline]
use std::fmt;
use std::mem;
use rustc_data_structures::sync::Lrc;
+use rustc_macros::HashStable_Generic;
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum BinOpToken {
}
}
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub enum LitKind {
Bool, // AST only, must never appear in a `Token`
Byte,
}
/// A literal token.
-#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
pub struct Lit {
pub kind: LitKind,
pub symbol: Symbol,
where V: Visitor<'a>,
{
visitor.visit_ident(variant.ident);
+ visitor.visit_vis(&variant.vis);
visitor.visit_variant_data(&variant.data);
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
walk_list!(visitor, visit_attribute, &variant.attrs);
}
pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) {
+ visitor.visit_vis(&trait_item.vis);
visitor.visit_ident(trait_item.ident);
walk_list!(visitor, visit_attribute, &trait_item.attrs);
visitor.visit_generics(&trait_item.generics);
}
pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
+ let vis_span = span.shrink_to_lo();
let fields: Vec<_> = tys.into_iter().map(|ty| {
ast::StructField {
span: ty.span,
ty,
ident: None,
- vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited),
+ vis: respan(vis_span, ast::VisibilityKind::Inherited),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
is_placeholder: false,
disr_expr: None,
id: ast::DUMMY_NODE_ID,
ident,
+ vis: respan(vis_span, ast::VisibilityKind::Inherited),
span,
is_placeholder: false,
}
+++ /dev/null
-use rustc_parse::validate_attr;
-use syntax::attr::HasAttrs;
-use syntax::feature_gate::{
- feature_err,
- EXPLAIN_STMT_ATTR_SYNTAX,
- Features,
- get_features,
- GateIssue,
-};
-use syntax::attr;
-use syntax::ast;
-use syntax::edition::Edition;
-use syntax::mut_visit::*;
-use syntax::ptr::P;
-use syntax::sess::ParseSess;
-use syntax::util::map_in_place::MapInPlace;
-use syntax_pos::symbol::sym;
-
-use errors::Applicability;
-use smallvec::SmallVec;
-
-/// A folder that strips out items that do not belong in the current configuration.
-pub struct StripUnconfigured<'a> {
- pub sess: &'a ParseSess,
- pub features: Option<&'a Features>,
-}
-
-// `cfg_attr`-process the crate's attributes and compute the crate's features.
-pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition,
- allow_features: &Option<Vec<String>>) -> (ast::Crate, Features) {
- let features;
- {
- let mut strip_unconfigured = StripUnconfigured {
- sess,
- features: None,
- };
-
- let unconfigured_attrs = krate.attrs.clone();
- let err_count = sess.span_diagnostic.err_count();
- if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
- krate.attrs = attrs;
- } else { // the entire crate is unconfigured
- krate.attrs = Vec::new();
- krate.module.items = Vec::new();
- return (krate, Features::new());
- }
-
- features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);
-
- // Avoid reconfiguring malformed `cfg_attr`s
- if err_count == sess.span_diagnostic.err_count() {
- strip_unconfigured.features = Some(&features);
- strip_unconfigured.configure(unconfigured_attrs);
- }
- }
-
- (krate, features)
-}
-
-#[macro_export]
-macro_rules! configure {
- ($this:ident, $node:ident) => {
- match $this.configure($node) {
- Some(node) => node,
- None => return Default::default(),
- }
- }
-}
-
-impl<'a> StripUnconfigured<'a> {
- pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
- self.process_cfg_attrs(&mut node);
- if self.in_cfg(node.attrs()) { Some(node) } else { None }
- }
-
- /// Parse and expand all `cfg_attr` attributes into a list of attributes
- /// that are within each `cfg_attr` that has a true configuration predicate.
- ///
- /// Gives compiler warnigns if any `cfg_attr` does not contain any
- /// attributes and is in the original source code. Gives compiler errors if
- /// the syntax of any `cfg_attr` is incorrect.
- pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: &mut T) {
- node.visit_attrs(|attrs| {
- attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
- });
- }
-
- /// Parse and expand a single `cfg_attr` attribute into a list of attributes
- /// when the configuration predicate is true, or otherwise expand into an
- /// empty list of attributes.
- ///
- /// Gives a compiler warning when the `cfg_attr` contains no attributes and
- /// is in the original source file. Gives a compiler error if the syntax of
- /// the attribute is incorrect.
- fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
- if !attr.has_name(sym::cfg_attr) {
- return vec![attr];
- }
- if attr.get_normal_item().tokens.is_empty() {
- self.sess.span_diagnostic
- .struct_span_err(
- attr.span,
- "malformed `cfg_attr` attribute input",
- ).span_suggestion(
- attr.span,
- "missing condition and attribute",
- "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(),
- Applicability::HasPlaceholders,
- ).note("for more information, visit \
- <https://doc.rust-lang.org/reference/conditional-compilation.html\
- #the-cfg_attr-attribute>")
- .emit();
- return vec![];
- }
-
- let res = rustc_parse::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr());
- let (cfg_predicate, expanded_attrs) = match res {
- Ok(result) => result,
- Err(mut e) => {
- e.emit();
- return vec![];
- }
- };
-
- // Lint on zero attributes in source.
- if expanded_attrs.is_empty() {
- return vec![attr];
- }
-
- // At this point we know the attribute is considered used.
- attr::mark_used(&attr);
-
- if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
- // We call `process_cfg_attr` recursively in case there's a
- // `cfg_attr` inside of another `cfg_attr`. E.g.
- // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
- expanded_attrs.into_iter()
- .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item(
- attr.style,
- item,
- span,
- )))
- .collect()
- } else {
- vec![]
- }
- }
-
- /// Determines if a node with the given attributes should be included in this configuration.
- pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool {
- attrs.iter().all(|attr| {
- if !is_cfg(attr) {
- return true;
- }
-
- let error = |span, msg, suggestion: &str| {
- let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
- if !suggestion.is_empty() {
- err.span_suggestion(
- span,
- "expected syntax is",
- suggestion.into(),
- Applicability::MaybeIncorrect,
- );
- }
- err.emit();
- true
- };
-
- let meta_item = match validate_attr::parse_meta(self.sess, attr) {
- Ok(meta_item) => meta_item,
- Err(mut err) => { err.emit(); return true; }
- };
- let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() {
- nested_meta_items
- } else {
- return error(meta_item.span, "`cfg` is not followed by parentheses",
- "cfg(/* predicate */)");
- };
-
- if nested_meta_items.is_empty() {
- return error(meta_item.span, "`cfg` predicate is not specified", "");
- } else if nested_meta_items.len() > 1 {
- return error(nested_meta_items.last().unwrap().span(),
- "multiple `cfg` predicates are specified", "");
- }
-
- match nested_meta_items[0].meta_item() {
- Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
- None => error(nested_meta_items[0].span(),
- "`cfg` predicate key cannot be a literal", ""),
- }
- })
- }
-
- /// Visit attributes on expression and statements (but not attributes on items in blocks).
- fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
- // flag the offending attributes
- for attr in attrs.iter() {
- self.maybe_emit_expr_attr_err(attr);
- }
- }
-
- /// If attributes are not allowed on expressions, emit an error for `attr`
- pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) {
- if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
- let mut err = feature_err(self.sess,
- sym::stmt_expr_attributes,
- attr.span,
- GateIssue::Language,
- EXPLAIN_STMT_ATTR_SYNTAX);
-
- if attr.is_doc_comment() {
- err.help("`///` is for documentation comments. For a plain comment, use `//`.");
- }
-
- err.emit();
- }
- }
-
- pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
- let ast::ForeignMod { abi: _, items } = foreign_mod;
- items.flat_map_in_place(|item| self.configure(item));
- }
-
- pub fn configure_generic_params(&mut self, params: &mut Vec<ast::GenericParam>) {
- params.flat_map_in_place(|param| self.configure(param));
- }
-
- fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
- match vdata {
- ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) =>
- fields.flat_map_in_place(|field| self.configure(field)),
- ast::VariantData::Unit(_) => {}
- }
- }
-
- pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) {
- match item {
- ast::ItemKind::Struct(def, _generics) |
- ast::ItemKind::Union(def, _generics) => self.configure_variant_data(def),
- ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => {
- variants.flat_map_in_place(|variant| self.configure(variant));
- for variant in variants {
- self.configure_variant_data(&mut variant.data);
- }
- }
- _ => {}
- }
- }
-
- pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) {
- match expr_kind {
- ast::ExprKind::Match(_m, arms) => {
- arms.flat_map_in_place(|arm| self.configure(arm));
- }
- ast::ExprKind::Struct(_path, fields, _base) => {
- fields.flat_map_in_place(|field| self.configure(field));
- }
- _ => {}
- }
- }
-
- pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
- self.visit_expr_attrs(expr.attrs());
-
- // If an expr is valid to cfg away it will have been removed by the
- // outer stmt or expression folder before descending in here.
- // Anything else is always required, and thus has to error out
- // in case of a cfg attr.
- //
- // N.B., this is intentionally not part of the visit_expr() function
- // in order for filter_map_expr() to be able to avoid this check
- if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
- let msg = "removing an expression is not supported in this position";
- self.sess.span_diagnostic.span_err(attr.span, msg);
- }
-
- self.process_cfg_attrs(expr)
- }
-
- pub fn configure_pat(&mut self, pat: &mut P<ast::Pat>) {
- if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind {
- fields.flat_map_in_place(|field| self.configure(field));
- }
- }
-
- pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) {
- fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg));
- }
-}
-
-impl<'a> MutVisitor for StripUnconfigured<'a> {
- fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
- self.configure_foreign_mod(foreign_mod);
- noop_visit_foreign_mod(foreign_mod, self);
- }
-
- fn visit_item_kind(&mut self, item: &mut ast::ItemKind) {
- self.configure_item_kind(item);
- noop_visit_item_kind(item, self);
- }
-
- fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
- self.configure_expr(expr);
- self.configure_expr_kind(&mut expr.kind);
- noop_visit_expr(expr, self);
- }
-
- fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
- let mut expr = configure!(self, expr);
- self.configure_expr_kind(&mut expr.kind);
- noop_visit_expr(&mut expr, self);
- Some(expr)
- }
-
- fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
- noop_flat_map_stmt(configure!(self, stmt), self)
- }
-
- fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
- noop_flat_map_item(configure!(self, item), self)
- }
-
- fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
- noop_flat_map_impl_item(configure!(self, item), self)
- }
-
- fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
- noop_flat_map_trait_item(configure!(self, item), self)
- }
-
- fn visit_mac(&mut self, _mac: &mut ast::Mac) {
- // Don't configure interpolated AST (cf. issue #34171).
- // Interpolated AST will get configured once the surrounding tokens are parsed.
- }
-
- fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
- self.configure_pat(pat);
- noop_visit_pat(pat, self)
- }
-
- fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) {
- self.configure_fn_decl(&mut fn_decl);
- noop_visit_fn_decl(fn_decl, self);
- }
-}
-
-fn is_cfg(attr: &ast::Attribute) -> bool {
- attr.check_name(sym::cfg)
-}
-
-/// Process the potential `cfg` attributes on a module.
-/// Also determine if the module should be included in this configuration.
-pub fn process_configure_mod(
- sess: &ParseSess,
- cfg_mods: bool,
- attrs: &[ast::Attribute],
-) -> (bool, Vec<ast::Attribute>) {
- // Don't perform gated feature checking.
- let mut strip_unconfigured = StripUnconfigured { sess, features: None };
- let mut attrs = attrs.to_owned();
- strip_unconfigured.process_cfg_attrs(&mut attrs);
- (!cfg_mods || strip_unconfigured.in_cfg(&attrs), attrs)
-}
use crate::mbe::macro_rules::annotate_err_with_kind;
use crate::placeholders::{placeholder, PlaceholderExpander};
use crate::config::StripUnconfigured;
-use crate::configure;
+use rustc_parse::configure;
use rustc_parse::DirectoryOwnership;
use rustc_parse::parser::Parser;
pub mod base;
pub mod build;
pub mod expand;
-#[macro_use] pub mod config;
+pub use rustc_parse::config;
pub mod proc_macro;
crate mod mbe;
use crate::mbe::{self, TokenTree};
use rustc_parse::Directory;
-use rustc_parse::parser::{Parser, PathStyle};
+use rustc_parse::parser::{Parser, PathStyle, FollowedByType};
use syntax::ast::{Ident, Name};
use syntax::print::pprust;
use syntax::sess::ParseSess;
}
sym::path => token::NtPath(p.parse_path(PathStyle::Type)?),
sym::meta => token::NtMeta(p.parse_attr_item()?),
- sym::vis => token::NtVis(p.parse_visibility(true)?),
+ sym::vis => token::NtVis(p.parse_visibility(FollowedByType::Yes)?),
sym::lifetime => if p.check_lifetime() {
token::NtLifetime(p.expect_lifetime().ident)
} else {
-use crate::config::process_configure_mod;
-
use rustc_data_structures::sync::Lrc;
use rustc_parse::lexer::StringReader;
use syntax::token::{self, Token, TokenKind};
ParseSess::with_span_handler(
Handler::with_emitter(true, None, Box::new(emitter)),
sm,
- process_configure_mod,
)
}
-use crate::config::process_configure_mod;
use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse};
use rustc_parse::new_parser_from_source_str;
use std::path::PathBuf;
fn sess() -> ParseSess {
- ParseSess::new(FilePathMapping::empty(), process_configure_mod)
+ ParseSess::new(FilePathMapping::empty())
}
/// Parses an item.
tokens: None,
})]),
AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::TraitItem {
- id, span, ident, attrs, generics,
+ id, span, ident, vis, attrs, generics,
kind: ast::TraitItemKind::Macro(mac_placeholder()),
tokens: None,
}]),
id,
ident,
span,
+ vis,
is_placeholder: true,
}
])
-use crate::config::process_configure_mod;
use rustc_parse::{source_file_to_stream, new_parser_from_source_str, parser::Parser};
use syntax::ast;
use syntax::tokenstream::TokenStream;
/// Maps a string to tts, using a made-up filename.
crate fn string_to_stream(source_str: String) -> TokenStream {
- let ps = ParseSess::new(FilePathMapping::empty(), process_configure_mod);
+ let ps = ParseSess::new(FilePathMapping::empty());
source_file_to_stream(
&ps,
ps.source_map().new_source_file(PathBuf::from("bogofile").into(),
/// Parses a string, returns a crate.
crate fn string_to_crate(source_str : String) -> ast::Crate {
- let ps = ParseSess::new(FilePathMapping::empty(), process_configure_mod);
+ let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_crate_mod()
})
use std::fmt;
use std::str::FromStr;
+use rustc_macros::HashStable_Generic;
+
/// The edition of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable, Eq)]
+#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug,
+ RustcEncodable, RustcDecodable, Eq, HashStable_Generic)]
pub enum Edition {
// editions must be kept in order, oldest to newest
use crate::edition::Edition;
use crate::symbol::{kw, sym, Symbol};
+use rustc_macros::HashStable_Generic;
use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
/// A property of a macro expansion that determines how identifiers
/// produced by that expansion are resolved.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug,
+ RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum Transparency {
/// Identifier produced by a transparent expansion is always resolved at call-site.
/// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
}
/// Expansion kind.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum ExpnKind {
/// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
Root,
}
/// The kind of macro invocation or definition.
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable,
+ Hash, Debug, HashStable_Generic)]
pub enum MacroKind {
/// A bang macro `foo!()`.
Bang,
}
/// The kind of AST transform.
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum AstPass {
StdImports,
TestHarness,
}
/// The kind of compiler desugaring.
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum DesugaringKind {
/// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
/// However, we do not want to blame `c` for unreachability but rather say that `i`
#![feature(step_trait)]
use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
+use rustc_macros::HashStable_Generic;
pub mod source_map;
scoped_tls::scoped_thread_local!(pub static GLOBALS: Globals);
/// Differentiates between real files and common virtual files.
-#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)]
+#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash,
+ RustcDecodable, RustcEncodable, HashStable_Generic)]
pub enum FileName {
Real(PathBuf),
/// A macro. This includes the full name of the macro, so that there are no clashes.
use rustc_macros::symbols;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::{UseSpecializedDecodable, UseSpecializedEncodable};
+use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher};
use std::cmp::{PartialEq, PartialOrd, Ord};
use std::fmt;
}
}
+impl<CTX> HashStable<CTX> for Symbol {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.as_str().hash_stable(hcx, hasher);
+ }
+}
+
+impl<CTX> ToStableHashKey<CTX> for Symbol {
+ type KeyType = SymbolStr;
+
+ #[inline]
+ fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr {
+ self.as_str()
+ }
+}
+
// The `&'static str`s in this type actually point into the arena.
#[derive(Default)]
pub struct Interner {
fmt::Display::fmt(self.string, f)
}
}
+
+impl<CTX> HashStable<CTX> for SymbolStr {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.string.hash_stable(hcx, hasher)
+ }
+}
+
+impl<CTX> ToStableHashKey<CTX> for SymbolStr {
+ type KeyType = SymbolStr;
+
+ #[inline]
+ fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr {
+ self.clone()
+ }
+}
// CHECK-LABEL: @exhaustive_match
#[no_mangle]
-pub fn exhaustive_match(e: E, unit: ()) {
+pub fn exhaustive_match(e: E) -> u8 {
// CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
// CHECK-NEXT: ]
// CHECK: [[B]]:
+// CHECK-NEXT: store i8 1, i8* %1, align 1
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
// CHECK: [[OTHERWISE]]:
// CHECK-NEXT: unreachable
// CHECK: [[A]]:
+// CHECK-NEXT: store i8 0, i8* %1, align 1
// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
match e {
- E::A => unit,
- E::B => unit,
+ E::A => 0,
+ E::B => 1,
}
}
--- /dev/null
+// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2
+
+// Ensure that `x?` has no overhead on `Result<T, E>` due to identity `match`es in lowering.
+// This requires inlining to trigger the MIR optimizations in `SimplifyArmIdentity`.
+
+#![crate_type = "lib"]
+
+type R = Result<u64, i32>;
+
+#[no_mangle]
+fn try_identity(x: R) -> R {
+// CHECK: start:
+// CHECK-NOT: br {{.*}}
+// CHECK ret void
+ let y = x?;
+ Ok(y)
+}
// START rustc.main.ConstProp.before.mir
// bb0: {
// ...
-// _2 = (FOO: u8);
+// _3 = const Scalar(AllocId(0).0x0) : &u8;
+// _2 = (*_3);
// ...
-// _3 = (FOO: u8);
-// _1 = Add(move _2, move _3);
+// _5 = const Scalar(AllocId(0).0x0) : &u8;
+// _4 = (*_5);
+// _1 = Add(move _2, move _4);
// ...
// }
// END rustc.main.ConstProp.before.mir
// ...
// _2 = const 2u8;
// ...
-// _3 = const 2u8;
-// _1 = Add(move _2, move _3);
+// _4 = const 2u8;
+// _1 = Add(move _2, move _4);
// ...
// }
// END rustc.main.ConstProp.after.mir
--- /dev/null
+fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> {
+ let y = x?;
+ Ok(y)
+}
+
+fn main() {
+ let _ = try_identity(Ok(0));
+}
+
+// END RUST SOURCE
+// START rustc.try_identity.SimplifyArmIdentity.before.mir
+// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
+// let mut _0: std::result::Result<u32, i32>;
+// let _2: u32;
+// let mut _3: std::result::Result<u32, i32>;
+// let mut _4: std::result::Result<u32, i32>;
+// let mut _5: isize;
+// let _6: i32;
+// let mut _7: !;
+// let mut _8: i32;
+// let mut _9: i32;
+// let _10: u32;
+// let mut _11: u32;
+// scope 1 {
+// }
+// scope 2 {
+// scope 3 {
+// scope 7 {
+// }
+// scope 8 {
+// let mut _12: i32;
+// }
+// }
+// }
+// scope 4 {
+// scope 5 {
+// }
+// }
+// scope 6 {
+// }
+// bb0: {
+// _5 = discriminant(_1);
+// switchInt(move _5) -> [0isize: bb4, 1isize: bb2, otherwise: bb1];
+// }
+// bb1: {
+// unreachable;
+// }
+// bb2: {
+// _6 = ((_1 as Err).0: i32);
+// ((_0 as Err).0: i32) = move _6;
+// discriminant(_0) = 1;
+// goto -> bb3;
+// }
+// bb3: {
+// return;
+// }
+// bb4: {
+// _10 = ((_1 as Ok).0: u32);
+// ((_0 as Ok).0: u32) = move _10;
+// discriminant(_0) = 0;
+// goto -> bb3;
+// }
+// }
+// END rustc.try_identity.SimplifyArmIdentity.before.mir
+
+// START rustc.try_identity.SimplifyArmIdentity.after.mir
+// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
+// let mut _0: std::result::Result<u32, i32>;
+// let _2: u32;
+// let mut _3: std::result::Result<u32, i32>;
+// let mut _4: std::result::Result<u32, i32>;
+// let mut _5: isize;
+// let _6: i32;
+// let mut _7: !;
+// let mut _8: i32;
+// let mut _9: i32;
+// let _10: u32;
+// let mut _11: u32;
+// scope 1 {
+// }
+// scope 2 {
+// scope 3 {
+// scope 7 {
+// }
+// scope 8 {
+// let mut _12: i32;
+// }
+// }
+// }
+// scope 4 {
+// scope 5 {
+// }
+// }
+// scope 6 {
+// }
+// bb0: {
+// _5 = discriminant(_1);
+// switchInt(move _5) -> [0isize: bb4, 1isize: bb2, otherwise: bb1];
+// }
+// bb1: {
+// unreachable;
+// }
+// bb2: {
+// _0 = move _1;
+// nop;
+// nop;
+// goto -> bb3;
+// }
+// bb3: {
+// return;
+// }
+// bb4: {
+// _0 = move _1;
+// nop;
+// nop;
+// goto -> bb3;
+// }
+// }
+// END rustc.try_identity.SimplifyArmIdentity.after.mir
+
+// START rustc.try_identity.SimplifyBranchSame.after.mir
+// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
+// let mut _0: std::result::Result<u32, i32>;
+// let _2: u32;
+// let mut _3: std::result::Result<u32, i32>;
+// let mut _4: std::result::Result<u32, i32>;
+// let mut _5: isize;
+// let _6: i32;
+// let mut _7: !;
+// let mut _8: i32;
+// let mut _9: i32;
+// let _10: u32;
+// let mut _11: u32;
+// scope 1 {
+// }
+// scope 2 {
+// scope 3 {
+// scope 7 {
+// }
+// scope 8 {
+// let mut _12: i32;
+// }
+// }
+// }
+// scope 4 {
+// scope 5 {
+// }
+// }
+// scope 6 {
+// }
+// bb0: {
+// _5 = discriminant(_1);
+// goto -> bb2;
+// }
+// bb1: {
+// return;
+// }
+// bb2: {
+// _0 = move _1;
+// nop;
+// nop;
+// goto -> bb1;
+// }
+// }
+// END rustc.try_identity.SimplifyBranchSame.after.mir
+
+// START rustc.try_identity.SimplifyLocals.after.mir
+// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
+// let mut _0: std::result::Result<u32, i32>;
+// let mut _2: isize;
+// scope 1 {
+// }
+// scope 2 {
+// scope 3 {
+// scope 7 {
+// }
+// scope 8 {
+// }
+// }
+// }
+// scope 4 {
+// scope 5 {
+// }
+// }
+// scope 6 {
+// }
+// bb0: {
+// _2 = discriminant(_1);
+// _0 = move _1;
+// return;
+// }
+// }
+// END rustc.try_identity.SimplifyLocals.after.mir
+++ /dev/null
--include ../tools.mk
-
-all:
- $(RUSTC) -o $(TMPDIR)/foo.out -Z unpretty=hir=foo input.rs
- $(RUSTC) -o $(TMPDIR)/nest_foo.out -Z unpretty=hir=nest::foo input.rs
- $(RUSTC) -o $(TMPDIR)/foo_method.out -Z unpretty=hir=foo_method input.rs
- diff -u $(TMPDIR)/foo.out foo.pp
- diff -u $(TMPDIR)/nest_foo.out nest_foo.pp
- diff -u $(TMPDIR)/foo_method.out foo_method.pp
+++ /dev/null
-
-pub fn foo() -> i32 { 45 } /* foo */
-
-
-pub fn foo() -> &'static str { "i am a foo." } /* nest::foo */
+++ /dev/null
-
-
-
-
-fn foo_method(self: &Self)
- -> &'static str { return "i am very similar to foo."; } /*
-nest::{{impl}}::foo_method */
+++ /dev/null
-#![crate_type="lib"]
-
-pub fn
-foo() -> i32
-{ 45 }
-
-pub fn bar() -> &'static str { "i am not a foo." }
-
-pub mod nest {
- pub fn foo() -> &'static str { "i am a foo." }
-
- struct S;
- impl S {
- fn foo_method(&self) -> &'static str {
- return "i am very similar to foo.";
- }
- }
-}
+++ /dev/null
-
-
-
-pub fn foo() -> &'static str { "i am a foo." } /* nest::foo */
use syntax::ptr::P;
use syntax::print::pprust;
use syntax::token;
-use syntax_expand::config::process_configure_mod;
use std::fmt;
// Copied out of syntax::util::parser_testing
}
fn sess() -> ParseSess {
- ParseSess::new(FilePathMapping::empty(), process_configure_mod)
+ ParseSess::new(FilePathMapping::empty())
}
fn check_expr_attrs(es: &str, expected: &[&str]) {
use std::path::Path;
use syntax::sess::ParseSess;
use syntax::source_map::FilePathMapping;
-use syntax_expand::config::process_configure_mod;
#[path = "mod_dir_simple/test.rs"]
mod gravy;
}
fn parse() {
- let parse_session = ParseSess::new(FilePathMapping::empty(), process_configure_mod);
+ let parse_session = ParseSess::new(FilePathMapping::empty());
let path = Path::new(file!());
let path = path.canonicalize().unwrap();
use syntax::mut_visit::{self, MutVisitor, visit_clobber};
use syntax::print::pprust;
use syntax::ptr::P;
-use syntax_expand::config::process_configure_mod;
fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
let src_as_string = src.to_string();
}
fn run() {
- let ps = ParseSess::new(FilePathMapping::empty(), process_configure_mod);
+ let ps = ParseSess::new(FilePathMapping::empty());
iter_exprs(2, &mut |mut e| {
// If the pretty printer is correct, then `parse(print(e))` should be identical to `e`,
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
+{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
| ^
error[E0013]: constant functions cannot refer to statics, use a constant instead
- --> $DIR/const-fn-not-safe-for-const.rs:25:5
+ --> $DIR/const-fn-not-safe-for-const.rs:25:6
|
LL | &Y
- | ^^
+ | ^
error: aborting due to 3 previous errors
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: cannot access `static` items in const fn
- --> $DIR/min_const_fn.rs:91:36
+ --> $DIR/min_const_fn.rs:91:37
|
LL | const fn foo26() -> &'static u32 { &BAR }
- | ^^^^
+ | ^^^
|
= note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
= help: add `#![feature(const_fn)]` to the crate attributes to enable
LL | let b: *mut u32 = &mut a;
| ^^^^^^ constants require immutable values
-error[E0019]: constant contains unimplemented expression type
+error[E0658]: dereferencing raw pointers in constants is unstable
--> $DIR/projection_qualif.rs:7:18
|
LL | unsafe { *b = 5; }
| ^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/51911
+ = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-error[E0658]: dereferencing raw pointers in constants is unstable
+error[E0019]: constant contains unimplemented expression type
--> $DIR/projection_qualif.rs:7:18
|
LL | unsafe { *b = 5; }
| ^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/51911
- = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
error: aborting due to 3 previous errors
LL | const C1: &'static mut [usize] = &mut [];
| ^^^^^^^ constants require immutable values
-error[E0017]: references in constants may only refer to immutable values
- --> $DIR/issue-17718-const-bad-values.rs:5:41
+error[E0013]: constants cannot refer to statics, use a constant instead
+ --> $DIR/issue-17718-const-bad-values.rs:5:46
|
LL | const C2: &'static mut usize = unsafe { &mut S };
- | ^^^^^^ constants require immutable values
+ | ^
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0017]: references in constants may only refer to immutable values
--> $DIR/issue-17718-const-bad-values.rs:5:41
|
LL | const C2: &'static mut usize = unsafe { &mut S };
- | ^^^^^^
+ | ^^^^^^ constants require immutable values
error: aborting due to 3 previous errors
error[E0013]: constants cannot refer to statics, use a constant instead
- --> $DIR/issue-17718-references.rs:9:28
+ --> $DIR/issue-17718-references.rs:9:29
|
LL | const T2: &'static usize = &S;
- | ^^
+ | ^
error[E0013]: constants cannot refer to statics, use a constant instead
--> $DIR/issue-17718-references.rs:14:19
error[E0013]: constants cannot refer to statics, use a constant instead
- --> $DIR/issue-18118-2.rs:4:9
+ --> $DIR/issue-18118-2.rs:4:10
|
LL | &p
- | ^^
+ | ^
error: aborting due to previous error
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
--> $DIR/issue-28433.rs:2:5
|
LL | pub Duck,
- | ^^^ `pub` not permitted here
+ | ^^^ `pub` not permitted here because it's implied
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
--> $DIR/issue-28433.rs:5:5
|
LL | pub(crate) Dove
- | ^^^^^^^^^^ `pub` not permitted here
+ | ^^^^^^^^^^
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0449`.
fn qux() -> Option<usize> {
let _ = if true {
});
-//~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+//~^ ERROR expected one of `async`
//~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
//~| ERROR expected identifier, found `;`
Some(4)
LL | });
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;`
--> $DIR/issue-60075.rs:6:11
|
LL | fn qux() -> Option<usize> {
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `...`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...`
--> $DIR/issue-32446.rs:4:11
|
LL | trait T { ... }
- | ^^^ expected one of 7 possible tokens
+ | ^^^ expected one of 9 possible tokens
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+// Here we check that a `:vis` macro matcher subsititued for the empty visibility
+// (`VisibilityKind::Inherited`) is accepted when used before an enum variant.
+
+fn main() {}
+
+macro_rules! mac_variant {
+ ($vis:vis MARKER) => {
+ enum Enum {
+ $vis Unit,
+
+ $vis Tuple(u8, u16),
+
+ $vis Struct { f: u8 },
+ }
+ }
+}
+
+mac_variant!(MARKER);
+
+// We also accept visibilities on variants syntactically but not semantically.
+#[cfg(FALSE)]
+enum E {
+ pub U,
+ pub(crate) T(u8),
+ pub(super) T { f: String }
+}
--- /dev/null
+// check-pass
+
+// Here we check that a `:vis` macro matcher subsititued for the empty visibility
+// (`VisibilityKind::Inherited`) is accepted when used before an item in a trait.
+
+fn main() {}
+
+macro_rules! mac_in_trait {
+ ($vis:vis MARKER) => {
+ $vis fn beta() {}
+
+ $vis const GAMMA: u8;
+
+ $vis type Delta;
+ }
+}
+
+trait Alpha {
+ mac_in_trait!(MARKER);
+}
+
+// We also accept visibilities on items in traits syntactically but not semantically.
+#[cfg(FALSE)]
+trait Foo {
+ pub fn bar();
+ pub(crate) type baz;
+ pub(super) const QUUX: u8;
+}
macro_rules! bah {
($a:expr) => ($a)
- //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
+ //~^ ERROR expected one of `async`
}
trait bar {
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2`
--> $DIR/trait-non-item-macros.rs:2:19
|
LL | ($a:expr) => ($a)
- | ^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+ | ^^ expected one of 8 possible tokens
...
LL | bah!(2);
| -------- in this macro invocation
trait T {
+//~^ ERROR `main` function not found in crate `missing_close_brace_in_trait`
fn foo(&self);
-pub(crate) struct Bar<T>(); //~ ERROR expected one of
+pub(crate) struct Bar<T>();
+//~^ ERROR expected one of
impl T for Bar<usize> {
fn foo(&self) {}
error: this file contains an un-closed delimiter
- --> $DIR/missing-close-brace-in-trait.rs:10:66
+ --> $DIR/missing-close-brace-in-trait.rs:12:66
|
LL | trait T {
| - un-closed delimiter
LL | fn main() {}
| ^
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found keyword `pub`
- --> $DIR/missing-close-brace-in-trait.rs:4:1
+error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
+ --> $DIR/missing-close-brace-in-trait.rs:5:12
|
-LL | trait T {
- | - unclosed delimiter
-LL | fn foo(&self);
- | -
- | |
- | expected one of 7 possible tokens
- | help: `}` may belong here
-LL |
LL | pub(crate) struct Bar<T>();
- | ^^^ unexpected token
+ | ^^^^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+
+error[E0601]: `main` function not found in crate `missing_close_brace_in_trait`
+ --> $DIR/missing-close-brace-in-trait.rs:1:1
+ |
+LL | / trait T {
+LL | |
+LL | | fn foo(&self);
+LL | |
+... |
+LL | |
+LL | | fn main() {}
+ | |_________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-trait.rs`
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0601`.
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
--> $DIR/trait-pub-assoc-const.rs:2:5
|
LL | pub const Foo: u32;
- | ^^^ `pub` not permitted here
+ | ^^^ `pub` not permitted here because it's implied
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0449`.
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
--> $DIR/trait-pub-assoc-ty.rs:2:5
|
LL | pub type Foo;
- | ^^^ `pub` not permitted here
+ | ^^^ `pub` not permitted here because it's implied
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0449`.
-error: unnecessary visibility qualifier
+error[E0449]: unnecessary visibility qualifier
--> $DIR/trait-pub-method.rs:2:5
|
LL | pub fn foo();
- | ^^^ `pub` not permitted here
+ | ^^^ `pub` not permitted here because it's implied
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0449`.
-// Check that we can manually implement an object
-// unsafe trait for its trait object
-//
+// Check that we can manually implement an object-unsafe trait for its trait object.
+
// run-pass
#![feature(object_safe_for_dispatch)]
let mut res = String::new();
- // Directly call static
+ // Directly call static.
res.push(Struct::stat()); // "A"
res.push(<dyn Bad>::stat()); // "AC"
// These look similar enough...
let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) };
- // Call virtual
+ // Call virtual.
res.push(s.virt()); // "ACB"
res.push(bad.virt()); // "ACBD"
- // Indirectly call static
+ // Indirectly call static.
res.push(s.indirect()); // "ACBDA"
res.push(bad.indirect()); // "ACBDAC"
- if &res != "ACBDAC" {
- panic!();
- }
+ assert_eq!(&res, "ACBDAC");
}
static C: &u32 = &A;
//~^ ERROR thread-local statics cannot be accessed at compile-time
-//~| ERROR thread-local variable borrowed past end of function
const D: u32 = A;
//~^ ERROR thread-local statics cannot be accessed at compile-time
const E: &u32 = &A;
//~^ ERROR thread-local statics cannot be accessed at compile-time
-//~| ERROR thread-local variable borrowed past end of function
const fn f() -> u32 {
A
| ^
error[E0625]: thread-local statics cannot be accessed at compile-time
- --> $DIR/thread-local-in-ctfe.rs:9:18
+ --> $DIR/thread-local-in-ctfe.rs:9:19
|
LL | static C: &u32 = &A;
- | ^^
-
-error[E0712]: thread-local variable borrowed past end of function
- --> $DIR/thread-local-in-ctfe.rs:9:18
- |
-LL | static C: &u32 = &A;
- | ^^- end of enclosing function is here
- | |
- | thread-local variables cannot be borrowed beyond the end of the function
+ | ^
error[E0625]: thread-local statics cannot be accessed at compile-time
- --> $DIR/thread-local-in-ctfe.rs:13:16
+ --> $DIR/thread-local-in-ctfe.rs:12:16
|
LL | const D: u32 = A;
| ^
error[E0625]: thread-local statics cannot be accessed at compile-time
- --> $DIR/thread-local-in-ctfe.rs:16:17
- |
-LL | const E: &u32 = &A;
- | ^^
-
-error[E0712]: thread-local variable borrowed past end of function
- --> $DIR/thread-local-in-ctfe.rs:16:17
+ --> $DIR/thread-local-in-ctfe.rs:15:18
|
LL | const E: &u32 = &A;
- | ^^- end of enclosing function is here
- | |
- | thread-local variables cannot be borrowed beyond the end of the function
+ | ^
error[E0625]: thread-local statics cannot be accessed at compile-time
- --> $DIR/thread-local-in-ctfe.rs:21:5
+ --> $DIR/thread-local-in-ctfe.rs:19:5
|
LL | A
| ^
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0712`.
// run-pass
-// Check that trait-objects without a principal codegen properly.
+// Check that trait objects without a principal codegen properly.
use std::sync::atomic::{AtomicUsize, Ordering};
use std::mem;
struct SetOnDrop<'a>(&'a AtomicUsize, [u8; 64]);
impl<'a> Drop for SetOnDrop<'a> {
fn drop(&mut self) {
- self.0.store(self.0.load(Ordering::Relaxed)+1, Ordering::Relaxed);
+ self.0.store(self.0.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
}
}
-Subproject commit 67a63f89d8c0e5b22fb52cc33274283819f41792
+Subproject commit 644e2a76a87a129f597dc40b47593fc8f72539cb