Auto merge of #111153 - Dylan-DPC:rollup-0pq0hh3, r=Dylan-DPC

Rollup of 11 pull requests

Successful merges:

 - #107978 (Correctly convert an NT path to a Win32 path in `read_link`)
 - #110436 (Support loading version information from xz tarballs)
 - #110791 (Implement negative bounds for internal testing purposes)
 - #110874 (Adjust obligation cause code for `find_and_report_unsatisfied_index_impl`)
 - #110908 (resolve: One more attempt to simplify `module_children`)
 - #110943 (interpret: fail more gracefully on uninit unsized locals)
 - #111062 (Don't bail out early when checking invalid `repr` attr)
 - #111069 (remove pointless `FIXME` in `bootstrap::download`)
 - #111086 (Remove `MemEncoder`)
 - #111097 (Avoid ICEing miri on layout query cycles)
 - #111112 (Add some triagebot notifications for nnethercote.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-05-03 20:02:30 +00:00
commit 473f916d83
91 changed files with 849 additions and 582 deletions

View File

@ -297,6 +297,7 @@ dependencies = [
"sha2", "sha2",
"tar", "tar",
"toml", "toml",
"xz2",
] ]
[[package]] [[package]]
@ -2060,9 +2061,9 @@ dependencies = [
[[package]] [[package]]
name = "lzma-sys" name = "lzma-sys"
version = "0.1.16" version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f24f76ec44a8ac23a31915d6e326bca17ce88da03096f1ff194925dc714dac99" checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -4059,6 +4060,7 @@ dependencies = [
"indexmap", "indexmap",
"rustc_macros", "rustc_macros",
"smallvec", "smallvec",
"tempfile",
"thin-vec", "thin-vec",
] ]
@ -5658,9 +5660,9 @@ dependencies = [
[[package]] [[package]]
name = "xz2" name = "xz2"
version = "0.1.6" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c" checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
dependencies = [ dependencies = [
"lzma-sys", "lzma-sys",
] ]

View File

@ -287,12 +287,20 @@ pub enum TraitBoundModifier {
/// No modifiers /// No modifiers
None, None,
/// `!Trait`
Negative,
/// `?Trait` /// `?Trait`
Maybe, Maybe,
/// `~const Trait` /// `~const Trait`
MaybeConst, MaybeConst,
/// `~const !Trait`
//
// This parses but will be rejected during AST validation.
MaybeConstNegative,
/// `~const ?Trait` /// `~const ?Trait`
// //
// This parses but will be rejected during AST validation. // This parses but will be rejected during AST validation.
@ -2446,6 +2454,16 @@ impl fmt::Debug for ImplPolarity {
} }
} }
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
pub enum BoundPolarity {
/// `Type: Trait`
Positive,
/// `Type: !Trait`
Negative(Span),
/// `Type: ?Trait`
Maybe(Span),
}
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum FnRetTy { pub enum FnRetTy {
/// Returns type is not specified. /// Returns type is not specified.

View File

@ -1368,13 +1368,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound { this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
GenericBound::Trait( GenericBound::Trait(
ty, ty,
TraitBoundModifier::None | TraitBoundModifier::MaybeConst, TraitBoundModifier::None
| TraitBoundModifier::MaybeConst
| TraitBoundModifier::Negative,
) => Some(this.lower_poly_trait_ref(ty, itctx)), ) => Some(this.lower_poly_trait_ref(ty, itctx)),
// `~const ?Bound` will cause an error during AST validation // `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds. // anyways, so treat it like `?Bound` as compilation proceeds.
GenericBound::Trait( GenericBound::Trait(
_, _,
TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe, TraitBoundModifier::Maybe
| TraitBoundModifier::MaybeConstMaybe
| TraitBoundModifier::MaybeConstNegative,
) => None, ) => None,
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() { if lifetime_bound.is_none() {
@ -2421,11 +2425,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TraitBoundModifier::None => hir::TraitBoundModifier::None, TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst, TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
TraitBoundModifier::Negative => {
if self.tcx.features().negative_bounds {
hir::TraitBoundModifier::Negative
} else {
hir::TraitBoundModifier::None
}
}
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a // `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
// placeholder for compilation to proceed. // placeholder for compilation to proceed.
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => { TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
hir::TraitBoundModifier::Maybe hir::TraitBoundModifier::Maybe
} }
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
} }
} }

View File

@ -206,7 +206,7 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here
.closure = closures cannot have `~const` trait bounds .closure = closures cannot have `~const` trait bounds
.function = this function is not `const`, so it cannot have `~const` trait bounds .function = this function is not `const`, so it cannot have `~const` trait bounds
ast_passes_optional_const_exclusive = `~const` and `?` are mutually exclusive ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
ast_passes_const_and_async = functions cannot be both `const` and `async` ast_passes_const_and_async = functions cannot be both `const` and `async`
.const = `const` because of this .const = `const` because of this
@ -235,3 +235,9 @@ ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using t
.help = remove one of these features .help = remove one of these features
ast_passes_show_span = {$msg} ast_passes_show_span = {$msg}
ast_passes_negative_bound_not_supported =
negative bounds are not supported
ast_passes_constraint_on_negative_bound =
associated type constraints not allowed on negative bounds

View File

@ -1168,12 +1168,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}); });
} }
(_, TraitBoundModifier::MaybeConstMaybe) => { (_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()}); self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" });
}
(_, TraitBoundModifier::MaybeConstNegative) => {
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" });
} }
_ => {} _ => {}
} }
} }
// Negative trait bounds are not allowed to have associated constraints
if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound
&& let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
{
for arg in &args.args {
if let ast::AngleBracketedArg::Constraint(constraint) = arg {
self.err_handler().emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
}
}
}
visit::walk_param_bound(self, bound) visit::walk_param_bound(self, bound)
} }

View File

@ -567,6 +567,7 @@ pub enum TildeConstReason {
pub struct OptionalConstExclusive { pub struct OptionalConstExclusive {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub modifier: &'static str,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -693,3 +694,17 @@ pub struct ShowSpan {
pub span: Span, pub span: Span,
pub msg: &'static str, pub msg: &'static str,
} }
#[derive(Diagnostic)]
#[diag(ast_passes_negative_bound_not_supported)]
pub struct NegativeBoundUnsupported {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_constraint_on_negative_bound)]
pub struct ConstraintOnNegativeBound {
#[primary_span]
pub span: Span,
}

View File

@ -603,6 +603,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental");
gate_all!(const_closures, "const closures are experimental"); gate_all!(const_closures, "const closures are experimental");
if !visitor.features.negative_bounds {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
sess.emit_err(errors::NegativeBoundUnsupported { span });
}
}
// All uses of `gate_all!` below this point were added in #65742, // All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded). // and subsequently disabled (with the non-early gating readded).
// We emit an early future-incompatible warning for these. // We emit an early future-incompatible warning for these.

View File

@ -1570,12 +1570,19 @@ impl<'a> State<'a> {
GenericBound::Trait(tref, modifier) => { GenericBound::Trait(tref, modifier) => {
match modifier { match modifier {
TraitBoundModifier::None => {} TraitBoundModifier::None => {}
TraitBoundModifier::Negative => {
self.word("!");
}
TraitBoundModifier::Maybe => { TraitBoundModifier::Maybe => {
self.word("?"); self.word("?");
} }
TraitBoundModifier::MaybeConst => { TraitBoundModifier::MaybeConst => {
self.word_space("~const"); self.word_space("~const");
} }
TraitBoundModifier::MaybeConstNegative => {
self.word_space("~const");
self.word("!");
}
TraitBoundModifier::MaybeConstMaybe => { TraitBoundModifier::MaybeConstMaybe => {
self.word_space("~const"); self.word_space("~const");
self.word("?"); self.word("?");

View File

@ -31,7 +31,7 @@ use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_serialize::opaque::{MemDecoder, MemEncoder}; use rustc_serialize::opaque::{FileEncoder, MemDecoder};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource}; use rustc_session::cstore::{self, CrateSource};
@ -39,6 +39,7 @@ use rustc_session::utils::NativeLibKind;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::DebuggerVisualizerFile; use rustc_span::DebuggerVisualizerFile;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub mod back; pub mod back;
@ -215,8 +216,11 @@ const RLINK_MAGIC: &[u8] = b"rustlink";
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
impl CodegenResults { impl CodegenResults {
pub fn serialize_rlink(codegen_results: &CodegenResults) -> Vec<u8> { pub fn serialize_rlink(
let mut encoder = MemEncoder::new(); rlink_file: &Path,
codegen_results: &CodegenResults,
) -> Result<usize, io::Error> {
let mut encoder = FileEncoder::new(rlink_file)?;
encoder.emit_raw_bytes(RLINK_MAGIC); encoder.emit_raw_bytes(RLINK_MAGIC);
// `emit_raw_bytes` is used to make sure that the version representation does not depend on // `emit_raw_bytes` is used to make sure that the version representation does not depend on
// Encoder's inner representation of `u32`. // Encoder's inner representation of `u32`.

View File

@ -337,7 +337,7 @@ fn valtree_into_mplace<'tcx>(
match ty.kind() { match ty.kind() {
ty::FnDef(_, _) => { ty::FnDef(_, _) => {
ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap(); // Zero-sized type, nothing to do.
} }
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf(); let scalar_int = valtree.unwrap_leaf();

View File

@ -245,6 +245,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
if self.layout.is_unsized() { if self.layout.is_unsized() {
if matches!(self.op, Operand::Immediate(Immediate::Uninit)) {
// Uninit unsized places shouldn't occur. In the interpreter we have them
// temporarily for unsized arguments before their value is put in; in ConstProp they
// remain uninit and this code can actually be reached.
throw_inval!(UninitUnsizedLocal);
}
// There are no unsized immediates. // There are no unsized immediates.
self.assert_mem_place().len(cx) self.assert_mem_place().len(cx)
} else { } else {

View File

@ -164,6 +164,8 @@ declare_features! (
(active, link_cfg, "1.14.0", None, None), (active, link_cfg, "1.14.0", None, None),
/// Allows the `multiple_supertrait_upcastable` lint. /// Allows the `multiple_supertrait_upcastable` lint.
(active, multiple_supertrait_upcastable, "1.69.0", None, None), (active, multiple_supertrait_upcastable, "1.69.0", None, None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
(incomplete, negative_bounds, "CURRENT_RUSTC_VERSION", None, None),
/// Allows using `#[omit_gdb_pretty_printer_section]`. /// Allows using `#[omit_gdb_pretty_printer_section]`.
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None), (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
/// Allows using `#[prelude_import]` on glob `use` items. /// Allows using `#[prelude_import]` on glob `use` items.

View File

@ -435,6 +435,7 @@ pub enum GenericArgsParentheses {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum TraitBoundModifier { pub enum TraitBoundModifier {
None, None,
Negative,
Maybe, Maybe,
MaybeConst, MaybeConst,
} }

View File

@ -665,6 +665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span: Span, span: Span,
binding_span: Option<Span>, binding_span: Option<Span>,
constness: ty::BoundConstness, constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
bounds: &mut Bounds<'tcx>, bounds: &mut Bounds<'tcx>,
speculative: bool, speculative: bool,
trait_ref_span: Span, trait_ref_span: Span,
@ -696,10 +697,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars); ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings); debug!(?poly_trait_ref, ?assoc_bindings);
bounds.push_trait_bound(tcx, poly_trait_ref, span, constness); bounds.push_trait_bound(tcx, poly_trait_ref, span, constness, polarity);
let mut dup_bindings = FxHashMap::default(); let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings { for binding in &assoc_bindings {
// Don't register additional associated type bounds for negative bounds,
// since we should have emitten an error for them earlier, and they will
// not be well-formed!
if polarity == ty::ImplPolarity::Negative {
self.tcx()
.sess
.delay_span_bug(binding.span, "negative trait bounds should not have bindings");
continue;
}
// Specify type to assert that error was already reported in `Err` case. // Specify type to assert that error was already reported in `Err` case.
let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding( let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
hir_id, hir_id,
@ -711,6 +722,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
binding_span.unwrap_or(binding.span), binding_span.unwrap_or(binding.span),
constness, constness,
only_self_bounds, only_self_bounds,
polarity,
); );
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above). // Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
} }
@ -743,6 +755,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait_ref: &hir::TraitRef<'_>, trait_ref: &hir::TraitRef<'_>,
span: Span, span: Span,
constness: ty::BoundConstness, constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>, bounds: &mut Bounds<'tcx>,
speculative: bool, speculative: bool,
@ -764,6 +777,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span, span,
binding_span, binding_span,
constness, constness,
polarity,
bounds, bounds,
speculative, speculative,
trait_ref_span, trait_ref_span,
@ -799,6 +813,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span, span,
binding_span, binding_span,
constness, constness,
ty::ImplPolarity::Positive,
bounds, bounds,
speculative, speculative,
trait_ref_span, trait_ref_span,
@ -961,16 +976,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for ast_bound in ast_bounds { for ast_bound in ast_bounds {
match ast_bound { match ast_bound {
hir::GenericBound::Trait(poly_trait_ref, modifier) => { hir::GenericBound::Trait(poly_trait_ref, modifier) => {
let constness = match modifier { let (constness, polarity) = match modifier {
hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst, hir::TraitBoundModifier::MaybeConst => {
hir::TraitBoundModifier::None => ty::BoundConstness::NotConst, (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
}
hir::TraitBoundModifier::None => {
(ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
}
hir::TraitBoundModifier::Negative => {
(ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
}
hir::TraitBoundModifier::Maybe => continue, hir::TraitBoundModifier::Maybe => continue,
}; };
let _ = self.instantiate_poly_trait_ref( let _ = self.instantiate_poly_trait_ref(
&poly_trait_ref.trait_ref, &poly_trait_ref.trait_ref,
poly_trait_ref.span, poly_trait_ref.span,
constness, constness,
polarity,
param_ty, param_ty,
bounds, bounds,
false, false,
@ -1088,6 +1110,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
path_span: Span, path_span: Span,
constness: ty::BoundConstness, constness: ty::BoundConstness,
only_self_bounds: OnlySelfBounds, only_self_bounds: OnlySelfBounds,
polarity: ty::ImplPolarity,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
// Given something like `U: SomeTrait<T = X>`, we want to produce a // Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat // predicate like `<U as SomeTrait>::T = X`. This is somewhat
@ -1438,6 +1461,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&trait_bound.trait_ref, &trait_bound.trait_ref,
trait_bound.span, trait_bound.span,
ty::BoundConstness::NotConst, ty::BoundConstness::NotConst,
ty::ImplPolarity::Positive,
dummy_self, dummy_self,
&mut bounds, &mut bounds,
false, false,

View File

@ -42,8 +42,14 @@ impl<'tcx> Bounds<'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
span: Span, span: Span,
constness: ty::BoundConstness, constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
) { ) {
self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span)); self.predicates.push((
trait_ref
.map_bound(|trait_ref| ty::TraitPredicate { trait_ref, constness, polarity })
.to_predicate(tcx),
span,
));
} }
pub fn push_projection_bound( pub fn push_projection_bound(

View File

@ -528,6 +528,7 @@ pub fn hir_trait_to_predicates<'tcx>(
hir_trait, hir_trait,
DUMMY_SP, DUMMY_SP,
ty::BoundConstness::NotConst, ty::BoundConstness::NotConst,
ty::ImplPolarity::Positive,
self_ty, self_ty,
&mut bounds, &mut bounds,
true, true,

View File

@ -2822,7 +2822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// but has nested obligations which are unsatisfied. // but has nested obligations which are unsatisfied.
for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() { for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() {
if let Some((_, index_ty, element_ty)) = if let Some((_, index_ty, element_ty)) =
self.find_and_report_unsatisfied_index_impl(expr.hir_id, base, base_t) self.find_and_report_unsatisfied_index_impl(base, base_t)
{ {
self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
return element_ty; return element_ty;
@ -2881,7 +2881,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// predicates cause this to be, so that the user can add them to fix their code. /// predicates cause this to be, so that the user can add them to fix their code.
fn find_and_report_unsatisfied_index_impl( fn find_and_report_unsatisfied_index_impl(
&self, &self,
index_expr_hir_id: HirId,
base_expr: &hir::Expr<'_>, base_expr: &hir::Expr<'_>,
base_ty: Ty<'tcx>, base_ty: Ty<'tcx>,
) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> { ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> {
@ -2914,13 +2913,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// in the first place. // in the first place.
ocx.register_obligations(traits::predicates_for_generics( ocx.register_obligations(traits::predicates_for_generics(
|idx, span| { |idx, span| {
traits::ObligationCause::new( cause.clone().derived_cause(
base_expr.span, ty::Binder::dummy(ty::TraitPredicate {
self.body_id, trait_ref: impl_trait_ref,
if span.is_dummy() { polarity: ty::ImplPolarity::Positive,
traits::ExprItemObligation(impl_def_id, index_expr_hir_id, idx) constness: ty::BoundConstness::NotConst,
} else { }),
traits::ExprBindingObligation(impl_def_id, span, index_expr_hir_id, idx) |derived| {
traits::ImplDerivedObligation(Box::new(
traits::ImplDerivedObligationCause {
derived,
impl_or_alias_def_id: impl_def_id,
impl_def_predicate_index: Some(idx),
span,
},
))
}, },
) )
}, },

View File

@ -200,6 +200,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
let bound_predicate = elaboratable.predicate().kind(); let bound_predicate = elaboratable.predicate().kind();
match bound_predicate.skip_binder() { match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
// Negative trait bounds do not imply any supertrait bounds
if data.polarity == ty::ImplPolarity::Negative {
return;
}
// Get predicates implied by the trait, or only super predicates if we only care about self predicates. // Get predicates implied by the trait, or only super predicates if we only care about self predicates.
let predicates = if self.only_self { let predicates = if self.only_self {
tcx.super_predicates_of(data.def_id()) tcx.super_predicates_of(data.def_id())

View File

@ -368,9 +368,8 @@ impl Linker {
} }
if sess.opts.unstable_opts.no_link { if sess.opts.unstable_opts.no_link {
let encoded = CodegenResults::serialize_rlink(&codegen_results);
let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
std::fs::write(&rlink_file, encoded) CodegenResults::serialize_rlink(&rlink_file, &codegen_results)
.map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
return Ok(()); return Ok(());
} }

View File

@ -1364,9 +1364,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.params_in_repr[def_id] <- params_in_repr); record!(self.tables.params_in_repr[def_id] <- params_in_repr);
if adt_def.is_enum() { if adt_def.is_enum() {
let module_children = tcx.module_children_non_reexports(local_def_id); let module_children = tcx.module_children_local(local_def_id);
record_array!(self.tables.module_children_non_reexports[def_id] <- record_array!(self.tables.module_children_non_reexports[def_id] <-
module_children.iter().map(|def_id| def_id.local_def_index)); module_children.iter().map(|child| child.res.def_id().index));
} else { } else {
// For non-enum, there is only one variant, and its def_id is the adt's. // For non-enum, there is only one variant, and its def_id is the adt's.
debug_assert_eq!(adt_def.variants().len(), 1); debug_assert_eq!(adt_def.variants().len(), 1);
@ -1412,12 +1412,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Encode this here because we don't do it in encode_def_ids. // Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else { } else {
let non_reexports = tcx.module_children_non_reexports(local_def_id); let module_children = tcx.module_children_local(local_def_id);
record_array!(self.tables.module_children_non_reexports[def_id] <- record_array!(self.tables.module_children_non_reexports[def_id] <-
non_reexports.iter().map(|def_id| def_id.local_def_index)); module_children.iter().filter(|child| child.reexport_chain.is_empty())
.map(|child| child.res.def_id().index));
record_defaulted_array!(self.tables.module_children_reexports[def_id] <- record_defaulted_array!(self.tables.module_children_reexports[def_id] <-
tcx.module_children_reexports(local_def_id)); module_children.iter().filter(|child| !child.reexport_chain.is_empty()));
} }
} }
@ -1676,9 +1678,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
hir::ItemKind::Trait(..) => { hir::ItemKind::Trait(..) => {
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id)); record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
let module_children = tcx.module_children_non_reexports(item.owner_id.def_id); let module_children = tcx.module_children_local(item.owner_id.def_id);
record_array!(self.tables.module_children_non_reexports[def_id] <- record_array!(self.tables.module_children_non_reexports[def_id] <-
module_children.iter().map(|def_id| def_id.local_def_index)); module_children.iter().map(|child| child.res.def_id().index));
let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id); let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
record_associated_item_def_ids(self, associated_item_def_ids); record_associated_item_def_ids(self, associated_item_def_ids);

View File

@ -357,10 +357,16 @@ define_tables! {
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>, associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>, opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
unused_generic_params: Table<DefIndex, UnusedGenericParams>, unused_generic_params: Table<DefIndex, UnusedGenericParams>,
// Reexported names are not associated with individual `DefId`s,
// e.g. a glob import can introduce a lot of names, all with the same `DefId`.
// That's why the encoded list needs to contain `ModChild` structures describing all the names
// individually instead of `DefId`s.
module_children_reexports: Table<DefIndex, LazyArray<ModChild>>, module_children_reexports: Table<DefIndex, LazyArray<ModChild>>,
- optional: - optional:
attributes: Table<DefIndex, LazyArray<ast::Attribute>>, attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
// For non-reexported names in a module every name is associated with a separate `DefId`,
// so we can take their names, visibilities etc from other encoded tables.
module_children_non_reexports: Table<DefIndex, LazyArray<DefIndex>>, module_children_non_reexports: Table<DefIndex, LazyArray<DefIndex>>,
associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>, associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>,
opt_def_kind: Table<DefIndex, DefKind>, opt_def_kind: Table<DefIndex, DefKind>,

View File

@ -32,6 +32,9 @@ middle_values_too_big =
middle_cannot_be_normalized = middle_cannot_be_normalized =
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
middle_cycle =
a cycle occurred during layout computation
middle_strict_coherence_needs_negative_coherence = middle_strict_coherence_needs_negative_coherence =
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
.label = due to this attribute .label = due to this attribute

View File

@ -134,6 +134,9 @@ pub enum InvalidProgramInfo<'tcx> {
FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
/// SizeOf of unsized type was requested. /// SizeOf of unsized type was requested.
SizeOfUnsizedType(Ty<'tcx>), SizeOfUnsizedType(Ty<'tcx>),
/// An unsized local was accessed without having been initialized.
/// This is not meaningful as we can't even have backing memory for such locals.
UninitUnsizedLocal,
} }
impl fmt::Display for InvalidProgramInfo<'_> { impl fmt::Display for InvalidProgramInfo<'_> {
@ -150,6 +153,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
Layout(ref err) => write!(f, "{err}"), Layout(ref err) => write!(f, "{err}"),
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"), FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"), SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
UninitUnsizedLocal => write!(f, "unsized local is used while uninitialized"),
} }
} }
} }

View File

@ -2414,26 +2414,17 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
/// Named module children from all items except `use` and `extern crate` imports. /// Named module children from all kinds of items, including imports.
/// /// In addition to regular items this list also includes struct and variant constructors, and
/// In addition to regular items this list also includes struct or variant constructors, and
/// items inside `extern {}` blocks because all of them introduce names into parent module. /// items inside `extern {}` blocks because all of them introduce names into parent module.
/// For non-reexported children every such name is associated with a separate `DefId`.
/// ///
/// Module here is understood in name resolution sense - it can be a `mod` item, /// Module here is understood in name resolution sense - it can be a `mod` item,
/// or a crate root, or an enum, or a trait. /// or a crate root, or an enum, or a trait.
pub fn module_children_non_reexports(self, def_id: LocalDefId) -> &'tcx [LocalDefId] {
self.resolutions(()).module_children_non_reexports.get(&def_id).map_or(&[], |v| &v[..])
}
/// Named module children from `use` and `extern crate` imports.
/// ///
/// Reexported names are not associated with individual `DefId`s, /// This is not a query, making it a query causes perf regressions
/// e.g. a glob import can introduce a lot of names, all with the same `DefId`. /// (probably due to hashing spans in `ModChild`ren).
/// That's why the list needs to contain `ModChild` structures describing all the names pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] {
/// individually instead of `DefId`s. self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..])
pub fn module_children_reexports(self, def_id: LocalDefId) -> &'tcx [ModChild] {
self.resolutions(()).module_children_reexports.get(&def_id).map_or(&[], |v| &v[..])
} }
} }

View File

@ -210,6 +210,7 @@ pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>), Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>), SizeOverflow(Ty<'tcx>),
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
Cycle,
} }
impl IntoDiagnostic<'_, !> for LayoutError<'_> { impl IntoDiagnostic<'_, !> for LayoutError<'_> {
@ -230,6 +231,9 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
diag.set_arg("failure_ty", e.get_type_for_failure()); diag.set_arg("failure_ty", e.get_type_for_failure());
diag.set_primary_message(fluent::middle_cannot_be_normalized); diag.set_primary_message(fluent::middle_cannot_be_normalized);
} }
LayoutError::Cycle => {
diag.set_primary_message(fluent::middle_cycle);
}
} }
diag diag
} }
@ -250,6 +254,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
t, t,
e.get_type_for_failure() e.get_type_for_failure()
), ),
LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
} }
} }
} }

View File

@ -165,8 +165,7 @@ pub struct ResolverGlobalCtxt {
pub effective_visibilities: EffectiveVisibilities, pub effective_visibilities: EffectiveVisibilities,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>, pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
pub module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>, pub module_children: LocalDefIdMap<Vec<ModChild>>,
pub module_children_reexports: LocalDefIdMap<Vec<ModChild>>,
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>, pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
pub main_def: Option<MainDefinition>, pub main_def: Option<MainDefinition>,
pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>, pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,

View File

@ -2816,6 +2816,9 @@ define_print_and_forward_display! {
if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl { if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
p!("~const "); p!("~const ");
} }
if let ty::ImplPolarity::Negative = self.polarity {
p!("!");
}
p!(print(self.trait_ref.print_only_trait_path())) p!(print(self.trait_ref.print_only_trait_path()))
} }

View File

@ -106,6 +106,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::F
} }
} }
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
Err(ty::layout::LayoutError::Cycle)
}
}
// item_and_field_ids should form a cycle where each field contains the // item_and_field_ids should form a cycle where each field contains the
// type in the next element in the list // type in the next element in the list
pub fn recursive_type_error( pub fn recursive_type_error(

View File

@ -615,13 +615,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
.help = `dyn` is only needed at the start of a trait `+`-separated list .help = `dyn` is only needed at the start of a trait `+`-separated list
.suggestion = remove this keyword .suggestion = remove this keyword
parse_negative_bounds_not_supported = negative bounds are not supported
.label = negative bounds are not supported
.suggestion = {$num_bounds ->
[one] remove the bound
*[other] remove the bounds
}
parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
@ -772,7 +765,8 @@ parse_assoc_lifetime = associated lifetimes are not supported
parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
parse_maybe_lifetime = `?` may only modify trait bounds, not lifetime bounds parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
.suggestion = remove the `{$sigil}`
parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
.suggestion = remove the parentheses .suggestion = remove the parentheses

View File

@ -2280,31 +2280,6 @@ pub(crate) struct InvalidDynKeyword {
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(parse_negative_bounds_not_supported)]
pub(crate) struct NegativeBoundsNotSupported {
#[primary_span]
pub negative_bounds: Vec<Span>,
#[label]
pub last_span: Span,
#[subdiagnostic]
pub sub: Option<NegativeBoundsNotSupportedSugg>,
}
#[derive(Subdiagnostic)]
#[suggestion(
parse_suggestion,
style = "tool-only",
code = "{fixed}",
applicability = "machine-applicable"
)]
pub(crate) struct NegativeBoundsNotSupportedSugg {
#[primary_span]
pub bound_list: Span,
pub num_bounds: usize,
pub fixed: String,
}
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
pub enum HelpUseLatestEdition { pub enum HelpUseLatestEdition {
#[help(parse_help_set_edition_cargo)] #[help(parse_help_set_edition_cargo)]
@ -2412,10 +2387,12 @@ pub(crate) struct TildeConstLifetime {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_maybe_lifetime)] #[diag(parse_modifier_lifetime)]
pub(crate) struct MaybeLifetime { pub(crate) struct ModifierLifetime {
#[primary_span] #[primary_span]
#[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
pub span: Span, pub span: Span,
pub sigil: &'static str,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View File

@ -1284,7 +1284,7 @@ impl<'a> Parser<'a> {
} }
self.bump(); // `+` self.bump(); // `+`
let bounds = self.parse_generic_bounds(None)?; let bounds = self.parse_generic_bounds()?;
let sum_span = ty.span.to(self.prev_token.span); let sum_span = ty.span.to(self.prev_token.span);
let sub = match &ty.kind { let sub = match &ty.kind {

View File

@ -78,7 +78,7 @@ impl<'a> Parser<'a> {
} }
self.restore_snapshot(snapshot); self.restore_snapshot(snapshot);
} }
self.parse_generic_bounds(colon_span)? self.parse_generic_bounds()?
} else { } else {
Vec::new() Vec::new()
}; };
@ -419,7 +419,7 @@ impl<'a> Parser<'a> {
// or with mandatory equality sign and the second type. // or with mandatory equality sign and the second type.
let ty = self.parse_ty_for_where_clause()?; let ty = self.parse_ty_for_where_clause()?;
if self.eat(&token::Colon) { if self.eat(&token::Colon) {
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; let bounds = self.parse_generic_bounds()?;
Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
span: lo.to(self.prev_token.span), span: lo.to(self.prev_token.span),
bound_generic_params: lifetime_defs, bound_generic_params: lifetime_defs,

View File

@ -788,11 +788,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and supertrait bounds. // Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon); let had_colon = self.eat(&token::Colon);
let span_at_colon = self.prev_token.span; let span_at_colon = self.prev_token.span;
let bounds = if had_colon { let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
self.parse_generic_bounds(Some(self.prev_token.span))?
} else {
Vec::new()
};
let span_before_eq = self.prev_token.span; let span_before_eq = self.prev_token.span;
if self.eat(&token::Eq) { if self.eat(&token::Eq) {
@ -802,7 +798,7 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span }); self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
} }
let bounds = self.parse_generic_bounds(None)?; let bounds = self.parse_generic_bounds()?;
generics.where_clause = self.parse_where_clause()?; generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?; self.expect_semi()?;
@ -883,7 +879,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds. // Parse optional colon and param bounds.
let bounds = let bounds =
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() }; if self.eat(&token::Colon) { self.parse_generic_bounds()? } else { Vec::new() };
let before_where_clause = self.parse_where_clause()?; let before_where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };

View File

@ -606,7 +606,7 @@ impl<'a> Parser<'a> {
let kind = if self.eat(&token::Colon) { let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound. // Parse associated type constraint bound.
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; let bounds = self.parse_generic_bounds()?;
AssocConstraintKind::Bound { bounds } AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) { } else if self.eat(&token::Eq) {
self.parse_assoc_equality_term(ident, self.prev_token.span)? self.parse_assoc_equality_term(ident, self.prev_token.span)?

View File

@ -3,8 +3,7 @@ use super::{Parser, PathStyle, TokenType};
use crate::errors::{ use crate::errors::{
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg, FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
ReturnTypesUseThinArrow, ReturnTypesUseThinArrow,
}; };
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@ -14,8 +13,9 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::{ use rustc_ast::{
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam,
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier,
TraitObjectSyntax, Ty, TyKind,
}; };
use rustc_errors::{Applicability, PResult}; use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
@ -23,10 +23,10 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol; use rustc_span::Symbol;
use thin_vec::{thin_vec, ThinVec}; use thin_vec::{thin_vec, ThinVec};
/// Any `?` or `~const` modifiers that appear at the start of a bound. /// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers { struct BoundModifiers {
/// `?Trait`. /// `?Trait`.
maybe: Option<Span>, bound_polarity: BoundPolarity,
/// `~const Trait`. /// `~const Trait`.
maybe_const: Option<Span>, maybe_const: Option<Span>,
@ -34,11 +34,13 @@ struct BoundModifiers {
impl BoundModifiers { impl BoundModifiers {
fn to_trait_bound_modifier(&self) -> TraitBoundModifier { fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
match (self.maybe, self.maybe_const) { match (self.bound_polarity, self.maybe_const) {
(None, None) => TraitBoundModifier::None, (BoundPolarity::Positive, None) => TraitBoundModifier::None,
(Some(_), None) => TraitBoundModifier::Maybe, (BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative,
(None, Some(_)) => TraitBoundModifier::MaybeConst, (BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe,
(Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe, (BoundPolarity::Positive, Some(_)) => TraitBoundModifier::MaybeConst,
(BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative,
(BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
} }
} }
} }
@ -368,7 +370,7 @@ impl<'a> Parser<'a> {
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
let bounds = self.parse_generic_bounds_common(allow_plus, None)?; let bounds = self.parse_generic_bounds_common(allow_plus)?;
if lt_no_plus { if lt_no_plus {
self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo }); self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
} }
@ -395,7 +397,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, TyKind> { ) -> PResult<'a, TyKind> {
if plus { if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?); bounds.append(&mut self.parse_generic_bounds()?);
} }
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
} }
@ -598,7 +600,7 @@ impl<'a> Parser<'a> {
} }
}) })
} }
let bounds = self.parse_generic_bounds(None)?; let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
} }
@ -629,7 +631,7 @@ impl<'a> Parser<'a> {
}; };
// Always parse bounds greedily for better error recovery. // Always parse bounds greedily for better error recovery.
let bounds = self.parse_generic_bounds(None)?; let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::TraitObject(bounds, syntax)) Ok(TyKind::TraitObject(bounds, syntax))
} }
@ -660,23 +662,15 @@ impl<'a> Parser<'a> {
} }
} }
pub(super) fn parse_generic_bounds( pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
&mut self, self.parse_generic_bounds_common(AllowPlus::Yes)
colon_span: Option<Span>,
) -> PResult<'a, GenericBounds> {
self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
} }
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`. /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
/// ///
/// See `parse_generic_bound` for the `BOUND` grammar. /// See `parse_generic_bound` for the `BOUND` grammar.
fn parse_generic_bounds_common( fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
&mut self,
allow_plus: AllowPlus,
colon_span: Option<Span>,
) -> PResult<'a, GenericBounds> {
let mut bounds = Vec::new(); let mut bounds = Vec::new();
let mut negative_bounds = Vec::new();
// In addition to looping while we find generic bounds: // In addition to looping while we find generic bounds:
// We continue even if we find a keyword. This is necessary for error recovery on, // We continue even if we find a keyword. This is necessary for error recovery on,
@ -693,19 +687,12 @@ impl<'a> Parser<'a> {
self.sess.emit_err(InvalidDynKeyword { span: self.token.span }); self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
self.bump(); self.bump();
} }
match self.parse_generic_bound()? { bounds.push(self.parse_generic_bound()?);
Ok(bound) => bounds.push(bound),
Err(neg_sp) => negative_bounds.push(neg_sp),
}
if allow_plus == AllowPlus::No || !self.eat_plus() { if allow_plus == AllowPlus::No || !self.eat_plus() {
break; break;
} }
} }
if !negative_bounds.is_empty() {
self.error_negative_bounds(colon_span, &bounds, negative_bounds);
}
Ok(bounds) Ok(bounds)
} }
@ -713,55 +700,22 @@ impl<'a> Parser<'a> {
fn can_begin_bound(&mut self) -> bool { fn can_begin_bound(&mut self) -> bool {
// This needs to be synchronized with `TokenKind::can_begin_bound`. // This needs to be synchronized with `TokenKind::can_begin_bound`.
self.check_path() self.check_path()
|| self.check_lifetime() || self.check_lifetime()
|| self.check(&token::Not) // Used for error reporting only. || self.check(&token::Not)
|| self.check(&token::Question) || self.check(&token::Question)
|| self.check(&token::Tilde) || self.check(&token::Tilde)
|| self.check_keyword(kw::For) || self.check_keyword(kw::For)
|| self.check(&token::OpenDelim(Delimiter::Parenthesis)) || self.check(&token::OpenDelim(Delimiter::Parenthesis))
}
fn error_negative_bounds(
&self,
colon_span: Option<Span>,
bounds: &[GenericBound],
negative_bounds: Vec<Span>,
) {
let sub = if let Some(bound_list) = colon_span {
let bound_list = bound_list.to(self.prev_token.span);
let mut new_bound_list = String::new();
if !bounds.is_empty() {
let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span()));
while let Some(Ok(snippet)) = snippets.next() {
new_bound_list.push_str(" + ");
new_bound_list.push_str(&snippet);
}
new_bound_list = new_bound_list.replacen(" +", ":", 1);
}
Some(NegativeBoundsNotSupportedSugg {
bound_list,
num_bounds: negative_bounds.len(),
fixed: new_bound_list,
})
} else {
None
};
let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub });
} }
/// Parses a bound according to the grammar: /// Parses a bound according to the grammar:
/// ```ebnf /// ```ebnf
/// BOUND = TY_BOUND | LT_BOUND /// BOUND = TY_BOUND | LT_BOUND
/// ``` /// ```
fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> { fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let anchor_lo = self.prev_token.span;
let lo = self.token.span; let lo = self.token.span;
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis)); let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
let inner_lo = self.token.span; let inner_lo = self.token.span;
let is_negative = self.eat(&token::Not);
let modifiers = self.parse_ty_bound_modifiers()?; let modifiers = self.parse_ty_bound_modifiers()?;
let bound = if self.token.is_lifetime() { let bound = if self.token.is_lifetime() {
@ -771,7 +725,7 @@ impl<'a> Parser<'a> {
self.parse_generic_ty_bound(lo, has_parens, modifiers)? self.parse_generic_ty_bound(lo, has_parens, modifiers)?
}; };
Ok(if is_negative { Err(anchor_lo.to(self.prev_token.span)) } else { Ok(bound) }) Ok(bound)
} }
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to: /// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
@ -799,8 +753,14 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::TildeConstLifetime { span }); self.sess.emit_err(errors::TildeConstLifetime { span });
} }
if let Some(span) = modifiers.maybe { match modifiers.bound_polarity {
self.sess.emit_err(errors::MaybeLifetime { span }); BoundPolarity::Positive => {}
BoundPolarity::Negative(span) => {
self.sess.emit_err(errors::ModifierLifetime { span, sigil: "!" });
}
BoundPolarity::Maybe(span) => {
self.sess.emit_err(errors::ModifierLifetime { span, sigil: "?" });
}
} }
} }
@ -843,9 +803,16 @@ impl<'a> Parser<'a> {
None None
}; };
let maybe = self.eat(&token::Question).then_some(self.prev_token.span); let bound_polarity = if self.eat(&token::Question) {
BoundPolarity::Maybe(self.prev_token.span)
} else if self.eat(&token::Not) {
self.sess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);
BoundPolarity::Negative(self.prev_token.span)
} else {
BoundPolarity::Positive
};
Ok(BoundModifiers { maybe, maybe_const }) Ok(BoundModifiers { bound_polarity, maybe_const })
} }
/// Parses a type bound according to: /// Parses a type bound according to:

View File

@ -101,12 +101,11 @@ impl CheckAttrVisitor<'_> {
item: Option<ItemLike<'_>>, item: Option<ItemLike<'_>>,
) { ) {
let mut doc_aliases = FxHashMap::default(); let mut doc_aliases = FxHashMap::default();
let mut is_valid = true;
let mut specified_inline = None; let mut specified_inline = None;
let mut seen = FxHashMap::default(); let mut seen = FxHashMap::default();
let attrs = self.tcx.hir().attrs(hir_id); let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs { for attr in attrs {
let attr_is_valid = match attr.name_or_empty() { match attr.name_or_empty() {
sym::do_not_recommend => self.check_do_not_recommend(attr.span, target), sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
sym::inline => self.check_inline(hir_id, attr, span, target), sym::inline => self.check_inline(hir_id, attr, span, target),
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target), sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
@ -188,7 +187,6 @@ impl CheckAttrVisitor<'_> {
sym::link_ordinal => self.check_link_ordinal(&attr, span, target), sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
_ => true, _ => true,
}; };
is_valid &= attr_is_valid;
// lint-only checks // lint-only checks
match attr.name_or_empty() { match attr.name_or_empty() {
@ -255,10 +253,6 @@ impl CheckAttrVisitor<'_> {
self.check_unused_attribute(hir_id, attr) self.check_unused_attribute(hir_id, attr)
} }
if !is_valid {
return;
}
self.check_repr(attrs, span, target, item, hir_id); self.check_repr(attrs, span, target, item, hir_id);
self.check_used(attrs, target); self.check_used(attrs, target);
} }

View File

@ -515,9 +515,11 @@ impl<'tcx> EmbargoVisitor<'tcx> {
let vis = self.tcx.local_visibility(item_id.owner_id.def_id); let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod);
} }
for export in self.tcx.module_children_reexports(module_def_id) { for child in self.tcx.module_children_local(module_def_id) {
if export.vis.is_accessible_from(defining_mod, self.tcx) // FIXME: Use module children for the logic above too.
&& let Res::Def(def_kind, def_id) = export.res if !child.reexport_chain.is_empty()
&& child.vis.is_accessible_from(defining_mod, self.tcx)
&& let Res::Def(def_kind, def_id) = child.res
&& let Some(def_id) = def_id.as_local() { && let Some(def_id) = def_id.as_local() {
let vis = self.tcx.local_visibility(def_id); let vis = self.tcx.local_visibility(def_id);
self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);

View File

@ -1261,14 +1261,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
*module.globs.borrow_mut() = Vec::new(); *module.globs.borrow_mut() = Vec::new();
if let Some(def_id) = module.opt_def_id() { if let Some(def_id) = module.opt_def_id() {
let mut non_reexports = Vec::new(); let mut children = Vec::new();
let mut reexports = Vec::new();
module.for_each_child(self, |this, ident, _, binding| { module.for_each_child(self, |this, ident, _, binding| {
let res = binding.res().expect_non_local(); let res = binding.res().expect_non_local();
if !binding.is_import() { if res != def::Res::Err && !binding.is_ambiguity() {
non_reexports.push(res.def_id().expect_local());
} else if res != def::Res::Err && !binding.is_ambiguity() {
let mut reexport_chain = SmallVec::new(); let mut reexport_chain = SmallVec::new();
let mut next_binding = binding; let mut next_binding = binding;
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
@ -1276,17 +1273,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
next_binding = binding; next_binding = binding;
} }
reexports.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
} }
}); });
// Should be fine because this code is only called for local modules. if !children.is_empty() {
let def_id = def_id.expect_local(); // Should be fine because this code is only called for local modules.
if !non_reexports.is_empty() { self.module_children.insert(def_id.expect_local(), children);
self.module_children_non_reexports.insert(def_id, non_reexports);
}
if !reexports.is_empty() {
self.module_children_reexports.insert(def_id, reexports);
} }
} }
} }

View File

@ -909,8 +909,7 @@ pub struct Resolver<'a, 'tcx> {
/// `CrateNum` resolutions of `extern crate` items. /// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>, extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>, module_children: LocalDefIdMap<Vec<ModChild>>,
module_children_reexports: LocalDefIdMap<Vec<ModChild>>,
trait_map: NodeMap<Vec<TraitCandidate>>, trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules. /// A map from nodes to anonymous modules.
@ -1260,8 +1259,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
lifetimes_res_map: Default::default(), lifetimes_res_map: Default::default(),
extra_lifetime_params_map: Default::default(), extra_lifetime_params_map: Default::default(),
extern_crate_map: Default::default(), extern_crate_map: Default::default(),
module_children_non_reexports: Default::default(), module_children: Default::default(),
module_children_reexports: Default::default(),
trait_map: NodeMap::default(), trait_map: NodeMap::default(),
underscore_disambiguator: 0, underscore_disambiguator: 0,
empty_module, empty_module,
@ -1399,8 +1397,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
has_pub_restricted, has_pub_restricted,
effective_visibilities, effective_visibilities,
extern_crate_map, extern_crate_map,
module_children_non_reexports: self.module_children_non_reexports, module_children: self.module_children,
module_children_reexports: self.module_children_reexports,
glob_map, glob_map,
maybe_unused_trait_imports, maybe_unused_trait_imports,
main_def, main_def,

View File

@ -10,3 +10,4 @@ thin-vec = "0.2.12"
[dev-dependencies] [dev-dependencies]
rustc_macros = { path = "../rustc_macros" } rustc_macros = { path = "../rustc_macros" }
tempfile = "3.2"

View File

@ -12,118 +12,14 @@ use std::ptr;
// Encoder // Encoder
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
pub struct MemEncoder {
pub data: Vec<u8>,
}
impl MemEncoder {
pub fn new() -> MemEncoder {
MemEncoder { data: vec![] }
}
#[inline]
pub fn position(&self) -> usize {
self.data.len()
}
pub fn finish(self) -> Vec<u8> {
self.data
}
}
macro_rules! write_leb128 {
($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
let old_len = $enc.data.len();
if MAX_ENCODED_LEN > $enc.data.capacity() - old_len {
$enc.data.reserve(MAX_ENCODED_LEN);
}
// SAFETY: The above check and `reserve` ensures that there is enough
// room to write the encoded value to the vector's internal buffer.
unsafe {
let buf = &mut *($enc.data.as_mut_ptr().add(old_len)
as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN]);
let encoded = leb128::$fun(buf, $value);
$enc.data.set_len(old_len + encoded.len());
}
}};
}
impl Encoder for MemEncoder {
#[inline]
fn emit_usize(&mut self, v: usize) {
write_leb128!(self, v, usize, write_usize_leb128)
}
#[inline]
fn emit_u128(&mut self, v: u128) {
write_leb128!(self, v, u128, write_u128_leb128);
}
#[inline]
fn emit_u64(&mut self, v: u64) {
write_leb128!(self, v, u64, write_u64_leb128);
}
#[inline]
fn emit_u32(&mut self, v: u32) {
write_leb128!(self, v, u32, write_u32_leb128);
}
#[inline]
fn emit_u16(&mut self, v: u16) {
self.data.extend_from_slice(&v.to_le_bytes());
}
#[inline]
fn emit_u8(&mut self, v: u8) {
self.data.push(v);
}
#[inline]
fn emit_isize(&mut self, v: isize) {
write_leb128!(self, v, isize, write_isize_leb128)
}
#[inline]
fn emit_i128(&mut self, v: i128) {
write_leb128!(self, v, i128, write_i128_leb128)
}
#[inline]
fn emit_i64(&mut self, v: i64) {
write_leb128!(self, v, i64, write_i64_leb128)
}
#[inline]
fn emit_i32(&mut self, v: i32) {
write_leb128!(self, v, i32, write_i32_leb128)
}
#[inline]
fn emit_i16(&mut self, v: i16) {
self.data.extend_from_slice(&v.to_le_bytes());
}
#[inline]
fn emit_raw_bytes(&mut self, s: &[u8]) {
self.data.extend_from_slice(s);
}
}
pub type FileEncodeResult = Result<usize, io::Error>; pub type FileEncodeResult = Result<usize, io::Error>;
/// `FileEncoder` encodes data to file via fixed-size buffer. /// `FileEncoder` encodes data to file via fixed-size buffer.
/// ///
/// When encoding large amounts of data to a file, using `FileEncoder` may be /// There used to be a `MemEncoder` type that encoded all the data into a
/// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the /// `Vec`. `FileEncoder` is better because its memory use is determined by the
/// `Vec` to file, as the latter uses as much memory as there is encoded data, /// size of the buffer, rather than the full length of the encoded data, and
/// while the former uses the fixed amount of memory allocated to the buffer. /// because it doesn't need to reallocate memory along the way.
/// `FileEncoder` also has the advantage of not needing to reallocate as data
/// is appended to it, but the disadvantage of requiring more error handling,
/// which has some runtime overhead.
pub struct FileEncoder { pub struct FileEncoder {
/// The input buffer. For adequate performance, we need more control over /// The input buffer. For adequate performance, we need more control over
/// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw /// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
@ -645,13 +541,6 @@ impl<'a> Decoder for MemDecoder<'a> {
// Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc., // Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
// since the default implementations call `encode` on their slices internally. // since the default implementations call `encode` on their slices internally.
impl Encodable<MemEncoder> for [u8] {
fn encode(&self, e: &mut MemEncoder) {
Encoder::emit_usize(e, self.len());
e.emit_raw_bytes(self);
}
}
impl Encodable<FileEncoder> for [u8] { impl Encodable<FileEncoder> for [u8] {
fn encode(&self, e: &mut FileEncoder) { fn encode(&self, e: &mut FileEncoder) {
Encoder::emit_usize(e, self.len()); Encoder::emit_usize(e, self.len());
@ -675,16 +564,6 @@ impl IntEncodedWithFixedSize {
pub const ENCODED_SIZE: usize = 8; pub const ENCODED_SIZE: usize = 8;
} }
impl Encodable<MemEncoder> for IntEncodedWithFixedSize {
#[inline]
fn encode(&self, e: &mut MemEncoder) {
let _start_pos = e.position();
e.emit_raw_bytes(&self.0.to_le_bytes());
let _end_pos = e.position();
debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
}
}
impl Encodable<FileEncoder> for IntEncodedWithFixedSize { impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
#[inline] #[inline]
fn encode(&self, e: &mut FileEncoder) { fn encode(&self, e: &mut FileEncoder) {

View File

@ -1,9 +1,10 @@
#![allow(rustc::internal)] #![allow(rustc::internal)]
use rustc_macros::{Decodable, Encodable}; use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder}; use rustc_serialize::opaque::{MemDecoder, FileEncoder};
use rustc_serialize::{Decodable, Encodable}; use rustc_serialize::{Decodable, Encodable};
use std::fmt::Debug; use std::fmt::Debug;
use std::fs;
#[derive(PartialEq, Clone, Debug, Encodable, Decodable)] #[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
struct Struct { struct Struct {
@ -27,18 +28,21 @@ struct Struct {
} }
fn check_round_trip< fn check_round_trip<
T: Encodable<MemEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug, T: Encodable<FileEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
>( >(
values: Vec<T>, values: Vec<T>,
) { ) {
let mut encoder = MemEncoder::new(); let tmpfile = tempfile::NamedTempFile::new().unwrap();
let tmpfile = tmpfile.path();
let mut encoder = FileEncoder::new(&tmpfile).unwrap();
for value in &values { for value in &values {
Encodable::encode(value, &mut encoder); Encodable::encode(value, &mut encoder);
} }
encoder.finish().unwrap();
let data = encoder.finish(); let data = fs::read(&tmpfile).unwrap();
let mut decoder = MemDecoder::new(&data[..], 0); let mut decoder = MemDecoder::new(&data[..], 0);
for value in values { for value in values {
let decoded = Decodable::decode(&mut decoder); let decoded = Decodable::decode(&mut decoder);
assert_eq!(value, decoded); assert_eq!(value, decoded);
@ -61,7 +65,7 @@ fn test_u8() {
#[test] #[test]
fn test_u16() { fn test_u16() {
for i in u16::MIN..u16::MAX { for i in [u16::MIN, 111, 3333, 55555, u16::MAX] {
check_round_trip(vec![1, 2, 3, i, i, i]); check_round_trip(vec![1, 2, 3, i, i, i]);
} }
} }
@ -92,7 +96,7 @@ fn test_i8() {
#[test] #[test]
fn test_i16() { fn test_i16() {
for i in i16::MIN..i16::MAX { for i in [i16::MIN, -100, 0, 101, i16::MAX] {
check_round_trip(vec![-1, 2, -3, i, i, i, 2]); check_round_trip(vec![-1, 2, -3, i, i, i, 2]);
} }
} }
@ -251,3 +255,41 @@ fn test_tuples() {
check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]); check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]);
check_round_trip(vec![(String::new(), "some string".to_string())]); check_round_trip(vec![(String::new(), "some string".to_string())]);
} }
#[test]
fn test_unit_like_struct() {
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct UnitLikeStruct;
check_round_trip(vec![UnitLikeStruct]);
}
#[test]
fn test_box() {
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct A {
foo: Box<[bool]>,
}
let obj = A { foo: Box::new([true, false]) };
check_round_trip(vec![obj]);
}
#[test]
fn test_cell() {
use std::cell::{Cell, RefCell};
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct A {
baz: isize,
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct B {
foo: Cell<bool>,
bar: RefCell<A>,
}
let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
check_round_trip(vec![obj]);
}

View File

@ -984,6 +984,7 @@ symbols! {
needs_panic_runtime, needs_panic_runtime,
neg, neg,
negate_unsigned, negate_unsigned,
negative_bounds,
negative_impls, negative_impls,
neon, neon,
never, never,

View File

@ -530,6 +530,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
associated_ty: Option<(&'static str, Ty<'tcx>)>, associated_ty: Option<(&'static str, Ty<'tcx>)>,
mut body_id: LocalDefId, mut body_id: LocalDefId,
) { ) {
if trait_pred.skip_binder().polarity == ty::ImplPolarity::Negative {
return;
}
let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
let self_ty = trait_pred.skip_binder().self_ty(); let self_ty = trait_pred.skip_binder().self_ty();

View File

@ -57,6 +57,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if obligation.polarity() == ty::ImplPolarity::Negative { if obligation.polarity() == ty::ImplPolarity::Negative {
self.assemble_candidates_for_trait_alias(obligation, &mut candidates); self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_from_impls(obligation, &mut candidates);
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
} else { } else {
self.assemble_candidates_for_trait_alias(obligation, &mut candidates); self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
@ -187,6 +188,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Keep only those bounds which may apply, and propagate overflow if it occurs. // Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in matching_bounds { for bound in matching_bounds {
if bound.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity {
continue;
}
// FIXME(oli-obk): it is suspicious that we are dropping the constness and // FIXME(oli-obk): it is suspicious that we are dropping the constness and
// polarity here. // polarity here.
let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;

View File

@ -328,6 +328,13 @@ impl<'tcx> WfPredicates<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let trait_ref = &trait_pred.trait_ref; let trait_ref = &trait_pred.trait_ref;
// Negative trait predicates don't require supertraits to hold, just
// that their substs are WF.
if trait_pred.polarity == ty::ImplPolarity::Negative {
self.compute_negative_trait_pred(trait_ref);
return;
}
// if the trait predicate is not const, the wf obligations should not be const as well. // if the trait predicate is not const, the wf obligations should not be const as well.
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
@ -393,6 +400,14 @@ impl<'tcx> WfPredicates<'tcx> {
); );
} }
// Compute the obligations that are required for `trait_ref` to be WF,
// given that it is a *negative* trait predicate.
fn compute_negative_trait_pred(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
for arg in trait_ref.substs {
self.compute(arg);
}
}
/// Pushes the obligations required for `trait_ref::Item` to be WF /// Pushes the obligations required for `trait_ref::Item` to be WF
/// into `self.out`. /// into `self.out`.
fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) { fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) {

View File

@ -919,6 +919,7 @@ fn symlink_noexist() {
#[test] #[test]
fn read_link() { fn read_link() {
let tmpdir = tmpdir();
if cfg!(windows) { if cfg!(windows) {
// directory symlink // directory symlink
assert_eq!(check!(fs::read_link(r"C:\Users\All Users")), Path::new(r"C:\ProgramData")); assert_eq!(check!(fs::read_link(r"C:\Users\All Users")), Path::new(r"C:\ProgramData"));
@ -933,8 +934,11 @@ fn read_link() {
Path::new(r"C:\Users") Path::new(r"C:\Users")
); );
} }
// Check that readlink works with non-drive paths on Windows.
let link = tmpdir.join("link_unc");
check!(symlink_dir(r"\\localhost\c$\", &link));
assert_eq!(check!(fs::read_link(&link)), Path::new(r"\\localhost\c$\"));
} }
let tmpdir = tmpdir();
let link = tmpdir.join("link"); let link = tmpdir.join("link");
if !got_symlink_permission(&tmpdir) { if !got_symlink_permission(&tmpdir) {
return; return;

View File

@ -313,6 +313,9 @@ pub(crate) fn make_bat_command_line(
/// ///
/// This is necessary because cmd.exe does not support verbatim paths. /// This is necessary because cmd.exe does not support verbatim paths.
pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> { pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
from_wide_to_user_path(to_u16s(path)?)
}
pub(crate) fn from_wide_to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
use crate::ptr; use crate::ptr;
use crate::sys::windows::fill_utf16_buf; use crate::sys::windows::fill_utf16_buf;
@ -325,8 +328,6 @@ pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
const N: u16 = b'N' as _; const N: u16 = b'N' as _;
const C: u16 = b'C' as _; const C: u16 = b'C' as _;
let mut path = to_u16s(path)?;
// Early return if the path is too long to remove the verbatim prefix. // Early return if the path is too long to remove the verbatim prefix.
const LEGACY_MAX_PATH: usize = 260; const LEGACY_MAX_PATH: usize = 260;
if path.len() > LEGACY_MAX_PATH { if path.len() > LEGACY_MAX_PATH {

View File

@ -477,7 +477,7 @@ impl File {
fn reparse_point( fn reparse_point(
&self, &self,
space: &mut Align8<[MaybeUninit<u8>]>, space: &mut Align8<[MaybeUninit<u8>]>,
) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> { ) -> io::Result<(c::DWORD, *mut c::REPARSE_DATA_BUFFER)> {
unsafe { unsafe {
let mut bytes = 0; let mut bytes = 0;
cvt({ cvt({
@ -496,7 +496,7 @@ impl File {
) )
})?; })?;
const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8); const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
Ok((bytes, space.0.as_ptr().cast::<c::REPARSE_DATA_BUFFER>())) Ok((bytes, space.0.as_mut_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
} }
} }
@ -506,22 +506,22 @@ impl File {
unsafe { unsafe {
let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag { let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
c::IO_REPARSE_TAG_SYMLINK => { c::IO_REPARSE_TAG_SYMLINK => {
let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER =
ptr::addr_of!((*buf).rest).cast(); ptr::addr_of_mut!((*buf).rest).cast();
assert!(info.is_aligned()); assert!(info.is_aligned());
( (
ptr::addr_of!((*info).PathBuffer).cast::<u16>(), ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
(*info).SubstituteNameOffset / 2, (*info).SubstituteNameOffset / 2,
(*info).SubstituteNameLength / 2, (*info).SubstituteNameLength / 2,
(*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0, (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0,
) )
} }
c::IO_REPARSE_TAG_MOUNT_POINT => { c::IO_REPARSE_TAG_MOUNT_POINT => {
let info: *const c::MOUNT_POINT_REPARSE_BUFFER = let info: *mut c::MOUNT_POINT_REPARSE_BUFFER =
ptr::addr_of!((*buf).rest).cast(); ptr::addr_of_mut!((*buf).rest).cast();
assert!(info.is_aligned()); assert!(info.is_aligned());
( (
ptr::addr_of!((*info).PathBuffer).cast::<u16>(), ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
(*info).SubstituteNameOffset / 2, (*info).SubstituteNameOffset / 2,
(*info).SubstituteNameLength / 2, (*info).SubstituteNameLength / 2,
false, false,
@ -535,13 +535,20 @@ impl File {
} }
}; };
let subst_ptr = path_buffer.add(subst_off.into()); let subst_ptr = path_buffer.add(subst_off.into());
let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize); let subst = slice::from_raw_parts_mut(subst_ptr, subst_len as usize);
// Absolute paths start with an NT internal namespace prefix `\??\` // Absolute paths start with an NT internal namespace prefix `\??\`
// We should not let it leak through. // We should not let it leak through.
if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) { if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) {
subst = &subst[4..]; // Turn `\??\` into `\\?\` (a verbatim path).
subst[1] = b'\\' as u16;
// Attempt to convert to a more user-friendly path.
let user = super::args::from_wide_to_user_path(
subst.iter().copied().chain([0]).collect(),
)?;
Ok(PathBuf::from(OsString::from_wide(&user.strip_suffix(&[0]).unwrap_or(&user))))
} else {
Ok(PathBuf::from(OsString::from_wide(subst)))
} }
Ok(PathBuf::from(OsString::from_wide(subst)))
} }
} }

View File

@ -427,7 +427,6 @@ impl Config {
fn download_toolchain( fn download_toolchain(
&self, &self,
// FIXME(ozkanonur) use CompilerMetadata instead of `version: &str`
version: &str, version: &str,
sysroot: &str, sysroot: &str,
stamp_key: &str, stamp_key: &str,

View File

@ -152,8 +152,9 @@ pub(crate) fn try_inline_glob(
// reexported by the glob, e.g. because they are shadowed by something else. // reexported by the glob, e.g. because they are shadowed by something else.
let reexports = cx let reexports = cx
.tcx .tcx
.module_children_reexports(current_mod) .module_children_local(current_mod)
.iter() .iter()
.filter(|child| !child.reexport_chain.is_empty())
.filter_map(|child| child.res.opt_def_id()) .filter_map(|child| child.res.opt_def_id())
.collect(); .collect();
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports)); let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));

View File

@ -2089,9 +2089,9 @@ pub(crate) fn reexport_chain<'tcx>(
import_def_id: LocalDefId, import_def_id: LocalDefId,
target_def_id: LocalDefId, target_def_id: LocalDefId,
) -> &'tcx [Reexport] { ) -> &'tcx [Reexport] {
for child in tcx.module_children_reexports(tcx.local_parent(import_def_id)) { for child in tcx.module_children_local(tcx.local_parent(import_def_id)) {
if child.res.opt_def_id() == Some(target_def_id.to_def_id()) if child.res.opt_def_id() == Some(target_def_id.to_def_id())
&& child.reexport_chain[0].id() == Some(import_def_id.to_def_id()) && child.reexport_chain.first().and_then(|r| r.id()) == Some(import_def_id.to_def_id())
{ {
return &child.reexport_chain; return &child.reexport_chain;
} }

View File

@ -439,6 +439,7 @@ impl clean::GenericBound {
let modifier_str = match modifier { let modifier_str = match modifier {
hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?", hir::TraitBoundModifier::Maybe => "?",
hir::TraitBoundModifier::Negative => "!",
// ~const is experimental; do not display those bounds in rustdoc // ~const is experimental; do not display those bounds in rustdoc
hir::TraitBoundModifier::MaybeConst => "", hir::TraitBoundModifier::MaybeConst => "",
}; };

View File

@ -1,53 +1,58 @@
<h2 id="layout" class="small-section-header"> {# #} <h2 id="layout" class="small-section-header"> {# #}
Layout<a href="#layout" class="anchor">§</a> {# #} Layout<a href="#layout" class="anchor">§</a> {# #}
</h2> {# #} </h2> {# #}
<div class="docblock"> {# #} <div class="docblock"> {# #}
{% match type_layout_size %} {% match type_layout_size %}
{% when Ok(type_layout_size) %} {% when Ok(type_layout_size) %}
<div class="warning"> {# #} <div class="warning"> {# #}
<p> {# #} <p> {# #}
<strong>Note:</strong> Most layout information is <strong>completely {#+ #} <strong>Note:</strong> Most layout information is <strong>completely {#+ #}
unstable</strong> and may even differ between compilations. {#+ #} unstable</strong> and may even differ between compilations. {#+ #}
The only exception is types with certain <code>repr(...)</code> {#+ #} The only exception is types with certain <code>repr(...)</code> {#+ #}
attributes. Please see the Rust References {#+ #} attributes. Please see the Rust References {#+ #}
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #} <a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
chapter for details on type layout guarantees. {# #} chapter for details on type layout guarantees. {# #}
</p> {# #} </p> {# #}
</div> {# #} </div> {# #}
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #} <p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
{% if !variants.is_empty() %} {% if !variants.is_empty() %}
<p> {# #} <p> {# #}
<strong>Size for each variant:</strong> {# #} <strong>Size for each variant:</strong> {# #}
</p> {# #} </p> {# #}
<ul> {# #} <ul> {# #}
{% for (name, layout_size) in variants %} {% for (name, layout_size) in variants %}
<li> {# #} <li> {# #}
<code>{{ name }}</code>: {#+ #} <code>{{ name }}</code>: {#+ #}
{{ layout_size|safe }} {{ layout_size|safe }}
</li> {# #} </li> {# #}
{% endfor %} {% endfor %}
</ul> {# #} </ul> {# #}
{% endif %} {% endif %}
{# This kind of layout error can occur with valid code, e.g. if you try to {# This kind of layout error can occur with valid code, e.g. if you try to
get the layout of a generic type such as `Vec<T>`. #} get the layout of a generic type such as `Vec<T>`. #}
{% when Err(LayoutError::Unknown(_)) %} {% when Err(LayoutError::Unknown(_)) %}
<p> {# #} <p> {# #}
<strong>Note:</strong> Unable to compute type layout, {#+ #} <strong>Note:</strong> Unable to compute type layout, {#+ #}
possibly due to this type having generic parameters. {#+ #} possibly due to this type having generic parameters. {#+ #}
Layout can only be computed for concrete, fully-instantiated types. {# #} Layout can only be computed for concrete, fully-instantiated types. {# #}
</p> {# #} </p> {# #}
{# This kind of error probably can't happen with valid code, but we don't {# This kind of error probably can't happen with valid code, but we don't
want to panic and prevent the docs from building, so we just let the want to panic and prevent the docs from building, so we just let the
user know that we couldn't compute the layout. #} user know that we couldn't compute the layout. #}
{% when Err(LayoutError::SizeOverflow(_)) %} {% when Err(LayoutError::SizeOverflow(_)) %}
<p> {# #} <p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #} <strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type was too big. {# #} the type was too big. {# #}
</p> {# #} </p> {# #}
{% when Err(LayoutError::NormalizationFailure(_, _)) %} {% when Err(LayoutError::NormalizationFailure(_, _)) %}
<p> {# #} <p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #} <strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type failed to be normalized. {# #} the type failed to be normalized. {# #}
</p> {# #} </p> {# #}
{% endmatch %} {% when Err(LayoutError::Cycle) %}
<p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type's layout depended on the type's layout itself. {# #}
</p> {# #}
{% endmatch %}
</div> {# #} </div> {# #}

View File

@ -533,6 +533,10 @@ pub(crate) fn from_trait_bound_modifier(
None => TraitBoundModifier::None, None => TraitBoundModifier::None,
Maybe => TraitBoundModifier::Maybe, Maybe => TraitBoundModifier::Maybe,
MaybeConst => TraitBoundModifier::MaybeConst, MaybeConst => TraitBoundModifier::MaybeConst,
// FIXME(negative-bounds): This bound should be rendered negative, but
// since that's experimental, maybe let's not add it to the rustdoc json
// API just now...
Negative => TraitBoundModifier::None,
} }
} }

View File

@ -136,14 +136,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
// is declared but also a reexport of itself producing two exports of the same // is declared but also a reexport of itself producing two exports of the same
// macro in the same module. // macro in the same module.
let mut inserted = FxHashSet::default(); let mut inserted = FxHashSet::default();
for export in self.cx.tcx.module_children_reexports(CRATE_DEF_ID) { for child in self.cx.tcx.module_children_local(CRATE_DEF_ID) {
if let Res::Def(DefKind::Macro(_), def_id) = export.res && if !child.reexport_chain.is_empty() &&
let Res::Def(DefKind::Macro(_), def_id) = child.res &&
let Some(local_def_id) = def_id.as_local() && let Some(local_def_id) = def_id.as_local() &&
self.cx.tcx.has_attr(def_id, sym::macro_export) && self.cx.tcx.has_attr(def_id, sym::macro_export) &&
inserted.insert(def_id) inserted.insert(def_id)
{ {
let item = self.cx.tcx.hir().expect_item(local_def_id); let item = self.cx.tcx.hir().expect_item(local_def_id);
top_level_module.items.insert((local_def_id, Some(item.ident.name)), (item, None, None)); top_level_module.items.insert((local_def_id, Some(item.ident.name)), (item, None, None));
} }
} }

View File

@ -9,6 +9,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
anyhow = "1.0.32" anyhow = "1.0.32"
flate2 = "1.0.16" flate2 = "1.0.16"
xz2 = "0.1.7"
tar = "0.4.29" tar = "0.4.29"
sha2 = "0.10.1" sha2 = "0.10.1"
rayon = "1.5.1" rayon = "1.5.1"

View File

@ -5,6 +5,7 @@ use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tar::Archive; use tar::Archive;
use xz2::read::XzDecoder;
const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
@ -175,9 +176,23 @@ impl Versions {
} }
fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> { fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?; for ext in ["xz", "gz"] {
let tarball = self.dist_path.join(tarball_name); let info =
self.load_version_from_tarball_inner(&self.dist_path.join(self.archive_name(
package,
DEFAULT_TARGET,
&format!("tar.{}", ext),
)?))?;
if info.present {
return Ok(info);
}
}
// If neither tarball is present, we fallback to returning the non-present info.
Ok(VersionInfo::default())
}
fn load_version_from_tarball_inner(&mut self, tarball: &Path) -> Result<VersionInfo, Error> {
let file = match File::open(&tarball) { let file = match File::open(&tarball) {
Ok(file) => file, Ok(file) => file,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => { Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
@ -187,7 +202,14 @@ impl Versions {
} }
Err(err) => return Err(err.into()), Err(err) => return Err(err.into()),
}; };
let mut tar = Archive::new(GzDecoder::new(file)); let mut tar: Archive<Box<dyn std::io::Read>> =
Archive::new(if tarball.extension().map_or(false, |e| e == "gz") {
Box::new(GzDecoder::new(file))
} else if tarball.extension().map_or(false, |e| e == "xz") {
Box::new(XzDecoder::new(file))
} else {
unimplemented!("tarball extension not recognized: {}", tarball.display())
});
let mut version = None; let mut version = None;
let mut git_commit = None; let mut git_commit = None;

View File

@ -0,0 +1,28 @@
//@error-pattern: a cycle occurred during layout computation
//~^ ERROR: cycle detected when computing layout of
use std::mem;
pub struct S<T: Tr> {
pub f: <T as Tr>::I,
}
pub trait Tr {
type I: Tr;
}
impl<T: Tr> Tr for S<T> {
type I = S<S<T>>;
}
impl Tr for () {
type I = ();
}
fn foo<T: Tr>() -> usize {
mem::size_of::<S<T>>()
}
fn main() {
println!("{}", foo::<S<()>>());
}

View File

@ -0,0 +1,28 @@
error[E0391]: cycle detected when computing layout of `S<S<()>>`
|
= note: ...which requires computing layout of `<S<()> as Tr>::I`...
= note: ...which again requires computing layout of `S<S<()>>`, completing the cycle
error: post-monomorphization error: a cycle occurred during layout computation
--> RUSTLIB/core/src/mem/mod.rs:LL:CC
|
LL | intrinsics::size_of::<T>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
|
= note: inside `std::mem::size_of::<S<S<()>>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC
note: inside `foo::<S<()>>`
--> $DIR/layout_cycle.rs:LL:CC
|
LL | mem::size_of::<S<T>>()
| ^^^^^^^^^^^^^^^^^^^^^^
note: inside `main`
--> $DIR/layout_cycle.rs:LL:CC
|
LL | println!("{}", foo::<S<()>>());
| ^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0391`.

View File

@ -552,6 +552,12 @@ impl Rewrite for ast::GenericBound {
ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
.rewrite(context, shape.offset_left(8)?) .rewrite(context, shape.offset_left(8)?)
.map(|s| format!("~const ?{}", s)), .map(|s| format!("~const ?{}", s)),
ast::TraitBoundModifier::Negative => poly_trait_ref
.rewrite(context, shape.offset_left(1)?)
.map(|s| format!("!{}", s)),
ast::TraitBoundModifier::MaybeConstNegative => poly_trait_ref
.rewrite(context, shape.offset_left(8)?)
.map(|s| format!("~const !{}", s)),
}; };
rewrite.map(|s| if has_paren { format!("({})", s) } else { s }) rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
} }

View File

@ -0,0 +1,11 @@
fn negative()
where
i32: !Copy,
{
}
fn maybe_const_negative()
where
i32: ~const !Copy,
{
}

View File

@ -1,34 +0,0 @@
// run-pass
#![allow(unused_imports)]
#![feature(rustc_private)]
extern crate rustc_macros;
extern crate rustc_serialize;
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
#[derive(Encodable, Decodable)]
struct A {
foo: Box<[bool]>,
}
fn main() {
let obj = A { foo: Box::new([true, false]) };
let mut encoder = MemEncoder::new();
obj.encode(&mut encoder);
let data = encoder.finish();
let mut decoder = MemDecoder::new(&data, 0);
let obj2 = A::decode(&mut decoder);
assert_eq!(obj.foo, obj2.foo);
}

View File

@ -1,44 +0,0 @@
// run-pass
#![allow(unused_imports)]
// This briefly tests the capability of `Cell` and `RefCell` to implement the
// `Encodable` and `Decodable` traits via `#[derive(Encodable, Decodable)]`
#![feature(rustc_private)]
extern crate rustc_macros;
extern crate rustc_serialize;
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
use std::cell::{Cell, RefCell};
#[derive(Encodable, Decodable)]
struct A {
baz: isize,
}
#[derive(Encodable, Decodable)]
struct B {
foo: Cell<bool>,
bar: RefCell<A>,
}
fn main() {
let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
let mut encoder = MemEncoder::new();
obj.encode(&mut encoder);
let data = encoder.finish();
let mut decoder = MemDecoder::new(&data, 0);
let obj2 = B::decode(&mut decoder);
assert_eq!(obj.foo.get(), obj2.foo.get());
assert_eq!(obj.bar.borrow().baz, obj2.bar.borrow().baz);
}

View File

@ -1,33 +0,0 @@
// run-pass
#![allow(unused_mut)]
#![allow(unused_imports)]
#![feature(rustc_private)]
extern crate rustc_macros;
extern crate rustc_serialize;
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct UnitLikeStruct;
pub fn main() {
let obj = UnitLikeStruct;
let mut encoder = MemEncoder::new();
obj.encode(&mut encoder);
let data = encoder.finish();
let mut decoder = MemDecoder::new(&data, 0);
let obj2 = UnitLikeStruct::decode(&mut decoder);
assert_eq!(obj, obj2);
}

View File

@ -0,0 +1,9 @@
// build-pass
//! Regression test for <https://github.com/rust-lang/rust/issues/68538>.
#![feature(unsized_fn_params)]
pub fn take_unsized_slice(s: [u8]) {
s[0];
}
fn main() {}

View File

@ -0,0 +1,4 @@
fn test<T: !Copy>() {}
//~^ ERROR negative bounds are not supported
fn main() {}

View File

@ -0,0 +1,8 @@
error: negative bounds are not supported
--> $DIR/feature-gate-negative_bounds.rs:1:12
|
LL | fn test<T: !Copy>() {}
| ^
error: aborting due to previous error

View File

@ -1,8 +1,8 @@
error: negative bounds are not supported error: negative bounds are not supported
--> $DIR/issue-58857.rs:4:7 --> $DIR/issue-58857.rs:4:9
| |
LL | impl<A: !Valid> Conj<A>{} LL | impl<A: !Valid> Conj<A>{}
| ^^^^^^^^ negative bounds are not supported | ^
error: aborting due to previous error error: aborting due to previous error

View File

@ -1,19 +0,0 @@
// run-rustfix
trait Tr {}
//~^ ERROR negative bounds are not supported
trait Tr2: SuperA {}
//~^ ERROR negative bounds are not supported
trait Tr3: SuperB {}
//~^ ERROR negative bounds are not supported
trait Tr4: SuperB + SuperD {}
//~^ ERROR negative bounds are not supported
trait Tr5 {}
//~^ ERROR negative bounds are not supported
trait SuperA {}
trait SuperB {}
trait SuperC {}
trait SuperD {}
fn main() {}

View File

@ -1,5 +1,3 @@
// run-rustfix
trait Tr: !SuperA {} trait Tr: !SuperA {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
trait Tr2: SuperA + !SuperB {} trait Tr2: SuperA + !SuperB {}
@ -7,10 +5,12 @@ trait Tr2: SuperA + !SuperB {}
trait Tr3: !SuperA + SuperB {} trait Tr3: !SuperA + SuperB {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
trait Tr4: !SuperA + SuperB trait Tr4: !SuperA + SuperB
+ !SuperC + SuperD {} //~^ ERROR negative bounds are not supported
+ !SuperC + SuperD {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
trait Tr5: !SuperA trait Tr5: !SuperA
+ !SuperB {} //~^ ERROR negative bounds are not supported
+ !SuperB {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
trait SuperA {} trait SuperA {}

View File

@ -1,36 +1,44 @@
error: negative bounds are not supported error: negative bounds are not supported
--> $DIR/issue-33418.rs:3:9 --> $DIR/issue-33418.rs:1:11
| |
LL | trait Tr: !SuperA {} LL | trait Tr: !SuperA {}
| ^^^^^^^^^ negative bounds are not supported | ^
error: negative bounds are not supported error: negative bounds are not supported
--> $DIR/issue-33418.rs:5:19 --> $DIR/issue-33418.rs:3:21
| |
LL | trait Tr2: SuperA + !SuperB {} LL | trait Tr2: SuperA + !SuperB {}
| ^^^^^^^^^ negative bounds are not supported | ^
error: negative bounds are not supported error: negative bounds are not supported
--> $DIR/issue-33418.rs:7:10 --> $DIR/issue-33418.rs:5:12
| |
LL | trait Tr3: !SuperA + SuperB {} LL | trait Tr3: !SuperA + SuperB {}
| ^^^^^^^^^ negative bounds are not supported | ^
error: negative bounds are not supported error: negative bounds are not supported
--> $DIR/issue-33418.rs:9:10 --> $DIR/issue-33418.rs:7:12
| |
LL | trait Tr4: !SuperA + SuperB LL | trait Tr4: !SuperA + SuperB
| ^^^^^^^^^ | ^
LL | + !SuperC + SuperD {}
| ^^^^^^^^^ negative bounds are not supported
error: negative bounds are not supported error: negative bounds are not supported
--> $DIR/issue-33418.rs:12:10 --> $DIR/issue-33418.rs:9:3
|
LL | + !SuperC + SuperD {}
| ^
error: negative bounds are not supported
--> $DIR/issue-33418.rs:11:12
| |
LL | trait Tr5: !SuperA LL | trait Tr5: !SuperA
| ^^^^^^^^^ | ^
LL | + !SuperB {}
| ^^^^^^^^^ negative bounds are not supported
error: aborting due to 5 previous errors error: negative bounds are not supported
--> $DIR/issue-33418.rs:13:3
|
LL | + !SuperB {}
| ^
error: aborting due to 7 previous errors

View File

@ -6,9 +6,12 @@
fn main() {} fn main() {}
pub fn f1<T>() {} pub fn f1<T: 'static>() {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
pub fn f2<'a, T: Ord>() {} //~| ERROR `!` may only modify trait bounds, not lifetime bound
pub fn f2<'a, T: Ord + 'a>() {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
pub fn f3<'a, T: Ord>() {} //~| ERROR `!` may only modify trait bounds, not lifetime bound
pub fn f3<'a, T: 'a + Ord>() {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
//~| ERROR `!` may only modify trait bounds, not lifetime bound

View File

@ -8,7 +8,10 @@ fn main() {}
pub fn f1<T: !'static>() {} pub fn f1<T: !'static>() {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
//~| ERROR `!` may only modify trait bounds, not lifetime bound
pub fn f2<'a, T: Ord + !'a>() {} pub fn f2<'a, T: Ord + !'a>() {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
//~| ERROR `!` may only modify trait bounds, not lifetime bound
pub fn f3<'a, T: !'a + Ord>() {} pub fn f3<'a, T: !'a + Ord>() {}
//~^ ERROR negative bounds are not supported //~^ ERROR negative bounds are not supported
//~| ERROR `!` may only modify trait bounds, not lifetime bound

View File

@ -1,20 +1,38 @@
error: negative bounds are not supported error: `!` may only modify trait bounds, not lifetime bounds
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:12 --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:14
| |
LL | pub fn f1<T: !'static>() {} LL | pub fn f1<T: !'static>() {}
| ^^^^^^^^^^ negative bounds are not supported | ^
error: negative bounds are not supported error: `!` may only modify trait bounds, not lifetime bounds
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:22 --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:12:24
| |
LL | pub fn f2<'a, T: Ord + !'a>() {} LL | pub fn f2<'a, T: Ord + !'a>() {}
| ^^^^^ negative bounds are not supported | ^
error: negative bounds are not supported error: `!` may only modify trait bounds, not lifetime bounds
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:13:16 --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:15:18
| |
LL | pub fn f3<'a, T: !'a + Ord>() {} LL | pub fn f3<'a, T: !'a + Ord>() {}
| ^^^^^ negative bounds are not supported | ^
error: aborting due to 3 previous errors error: negative bounds are not supported
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:14
|
LL | pub fn f1<T: !'static>() {}
| ^
error: negative bounds are not supported
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:12:24
|
LL | pub fn f2<'a, T: Ord + !'a>() {}
| ^
error: negative bounds are not supported
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:15:18
|
LL | pub fn f3<'a, T: !'a + Ord>() {}
| ^
error: aborting due to 6 previous errors

View File

@ -15,3 +15,8 @@ pub struct OwO3 {
pub enum OwO4 { pub enum OwO4 {
UwU = 1, UwU = 1,
} }
#[repr(uwu)] //~ERROR: unrecognized representation hint
#[doc(owo)] //~WARN: unknown `doc` attribute
//~^ WARN: this was previously
pub struct Owo5;

View File

@ -30,6 +30,24 @@ LL | #[repr(uwu, u8)]
| |
= help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
error: aborting due to 4 previous errors warning: unknown `doc` attribute `owo`
--> $DIR/invalid_repr_list_help.rs:20:7
|
LL | #[doc(owo)]
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `#[warn(invalid_doc_attributes)]` on by default
error[E0552]: unrecognized representation hint
--> $DIR/invalid_repr_list_help.rs:19:8
|
LL | #[repr(uwu)]
| ^^^
|
= help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0552`. For more information about this error, try `rustc --explain E0552`.

View File

@ -0,0 +1,20 @@
#![feature(negative_bounds, associated_type_bounds)]
//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
trait Trait {
type Assoc;
}
fn test<T: !Trait<Assoc = i32>>() {}
//~^ ERROR associated type constraints not allowed on negative bounds
fn test2<T>() where T: !Trait<Assoc = i32> {}
//~^ ERROR associated type constraints not allowed on negative bounds
fn test3<T: !Trait<Assoc: Send>>() {}
//~^ ERROR associated type constraints not allowed on negative bounds
fn test4<T>() where T: !Trait<Assoc: Send> {}
//~^ ERROR associated type constraints not allowed on negative bounds
fn main() {}

View File

@ -0,0 +1,34 @@
error: associated type constraints not allowed on negative bounds
--> $DIR/associated-constraints.rs:8:19
|
LL | fn test<T: !Trait<Assoc = i32>>() {}
| ^^^^^^^^^^^
error: associated type constraints not allowed on negative bounds
--> $DIR/associated-constraints.rs:11:31
|
LL | fn test2<T>() where T: !Trait<Assoc = i32> {}
| ^^^^^^^^^^^
error: associated type constraints not allowed on negative bounds
--> $DIR/associated-constraints.rs:14:20
|
LL | fn test3<T: !Trait<Assoc: Send>>() {}
| ^^^^^^^^^^^
error: associated type constraints not allowed on negative bounds
--> $DIR/associated-constraints.rs:17:31
|
LL | fn test4<T>() where T: !Trait<Assoc: Send> {}
| ^^^^^^^^^^^
warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/associated-constraints.rs:1:12
|
LL | #![feature(negative_bounds, associated_type_bounds)]
| ^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error: aborting due to 4 previous errors; 1 warning emitted

View File

@ -0,0 +1,42 @@
#![feature(negative_bounds, negative_impls)]
//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
fn not_copy<T: !Copy>() {}
fn neg_param_env<T: !Copy>() {
not_copy::<T>();
}
fn pos_param_env<T: Copy>() {
not_copy::<T>();
//~^ ERROR the trait bound `T: !Copy` is not satisfied
}
fn unknown<T>() {
not_copy::<T>();
//~^ ERROR the trait bound `T: !Copy` is not satisfied
}
struct NotCopyable;
impl !Copy for NotCopyable {}
fn neg_impl() {
not_copy::<NotCopyable>();
}
#[derive(Copy, Clone)]
struct Copyable;
fn pos_impl() {
not_copy::<Copyable>();
//~^ ERROR the trait bound `Copyable: !Copy` is not satisfied
}
struct NotNecessarilyCopyable;
fn unknown_impl() {
not_copy::<NotNecessarilyCopyable>();
//~^ ERROR the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied
}
fn main() {}

View File

@ -0,0 +1,70 @@
warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/simple.rs:1:12
|
LL | #![feature(negative_bounds, negative_impls)]
| ^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: the trait bound `T: !Copy` is not satisfied
--> $DIR/simple.rs:11:16
|
LL | not_copy::<T>();
| ^ the trait `!Copy` is not implemented for `T`
|
note: required by a bound in `not_copy`
--> $DIR/simple.rs:4:16
|
LL | fn not_copy<T: !Copy>() {}
| ^^^^^ required by this bound in `not_copy`
error[E0277]: the trait bound `T: !Copy` is not satisfied
--> $DIR/simple.rs:16:16
|
LL | not_copy::<T>();
| ^ the trait `!Copy` is not implemented for `T`
|
note: required by a bound in `not_copy`
--> $DIR/simple.rs:4:16
|
LL | fn not_copy<T: !Copy>() {}
| ^^^^^ required by this bound in `not_copy`
error[E0277]: the trait bound `Copyable: !Copy` is not satisfied
--> $DIR/simple.rs:31:16
|
LL | not_copy::<Copyable>();
| ^^^^^^^^ the trait `!Copy` is not implemented for `Copyable`
|
= help: the trait `Copy` is implemented for `Copyable`
note: required by a bound in `not_copy`
--> $DIR/simple.rs:4:16
|
LL | fn not_copy<T: !Copy>() {}
| ^^^^^ required by this bound in `not_copy`
help: consider annotating `Copyable` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct Copyable;
|
error[E0277]: the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied
--> $DIR/simple.rs:38:16
|
LL | not_copy::<NotNecessarilyCopyable>();
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `!Copy` is not implemented for `NotNecessarilyCopyable`
|
note: required by a bound in `not_copy`
--> $DIR/simple.rs:4:16
|
LL | fn not_copy<T: !Copy>() {}
| ^^^^^ required by this bound in `not_copy`
help: consider annotating `NotNecessarilyCopyable` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotNecessarilyCopyable;
|
error: aborting due to 4 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.

View File

@ -4,11 +4,14 @@ error[E0277]: the trait bound `K: Hash` is not satisfied
LL | map[k] LL | map[k]
| ^^^ the trait `Hash` is not implemented for `K` | ^^^ the trait `Hash` is not implemented for `K`
| |
note: required by a bound in `<HashMap<K, V> as Index<&K>>` note: required for `HashMap<K, V>` to implement `Index<&K>`
--> $DIR/bad-index-due-to-nested.rs:9:8 --> $DIR/bad-index-due-to-nested.rs:7:12
| |
LL | impl<K, V> Index<&K> for HashMap<K, V>
| ^^^^^^^^^ ^^^^^^^^^^^^^
LL | where
LL | K: Hash, LL | K: Hash,
| ^^^^ required by this bound in `<HashMap<K, V> as Index<&K>>` | ---- unsatisfied trait bound introduced here
help: consider restricting type parameter `K` help: consider restricting type parameter `K`
| |
LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V {
@ -20,11 +23,14 @@ error[E0277]: the trait bound `V: Copy` is not satisfied
LL | map[k] LL | map[k]
| ^^^ the trait `Copy` is not implemented for `V` | ^^^ the trait `Copy` is not implemented for `V`
| |
note: required by a bound in `<HashMap<K, V> as Index<&K>>` note: required for `HashMap<K, V>` to implement `Index<&K>`
--> $DIR/bad-index-due-to-nested.rs:10:8 --> $DIR/bad-index-due-to-nested.rs:7:12
| |
LL | impl<K, V> Index<&K> for HashMap<K, V>
| ^^^^^^^^^ ^^^^^^^^^^^^^
...
LL | V: Copy, LL | V: Copy,
| ^^^^ required by this bound in `<HashMap<K, V> as Index<&K>>` | ---- unsatisfied trait bound introduced here
help: consider restricting type parameter `V` help: consider restricting type parameter `V`
| |
LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V { LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V {

View File

@ -475,10 +475,10 @@ cc = ["@rust-lang/style"]
[mentions."Cargo.lock"] [mentions."Cargo.lock"]
message = """ message = """
These commits modify the `Cargo.lock` file. Random changes to `Cargo.lock` can be introduced when switching branches and rebasing PRs. These commits modify the `Cargo.lock` file. Unintentional changes to `Cargo.lock` can be introduced when switching branches and rebasing PRs.
This was probably unintentional and should be reverted before this PR is merged.
If this was intentional then you can ignore this comment. If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.
""" """
[mentions."src/tools/x"] [mentions."src/tools/x"]
@ -489,6 +489,14 @@ message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appro
[mentions."src/bootstrap/defaults/config.codegen.toml"] [mentions."src/bootstrap/defaults/config.codegen.toml"]
message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync." message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync."
[mentions."tests/ui/deriving/deriving-all-codegen.stdout"]
message = "Changes to the code generated for builtin derived traits."
cc = ["@nnethercote"]
[mentions."tests/ui/stats/hir-stats.stderr"]
message = "Changes to the size of AST and/or HIR nodes."
cc = ["@nnethercote"]
[assign] [assign]
warn_non_default_branch = true warn_non_default_branch = true
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"