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:
commit
473f916d83
10
Cargo.lock
10
Cargo.lock
@ -297,6 +297,7 @@ dependencies = [
|
||||
"sha2",
|
||||
"tar",
|
||||
"toml",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2060,9 +2061,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lzma-sys"
|
||||
version = "0.1.16"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f24f76ec44a8ac23a31915d6e326bca17ce88da03096f1ff194925dc714dac99"
|
||||
checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@ -4059,6 +4060,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"rustc_macros",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
@ -5658,9 +5660,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xz2"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c"
|
||||
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
|
||||
dependencies = [
|
||||
"lzma-sys",
|
||||
]
|
||||
|
@ -287,12 +287,20 @@ pub enum TraitBoundModifier {
|
||||
/// No modifiers
|
||||
None,
|
||||
|
||||
/// `!Trait`
|
||||
Negative,
|
||||
|
||||
/// `?Trait`
|
||||
Maybe,
|
||||
|
||||
/// `~const Trait`
|
||||
MaybeConst,
|
||||
|
||||
/// `~const !Trait`
|
||||
//
|
||||
// This parses but will be rejected during AST validation.
|
||||
MaybeConstNegative,
|
||||
|
||||
/// `~const ?Trait`
|
||||
//
|
||||
// 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)]
|
||||
pub enum FnRetTy {
|
||||
/// Returns type is not specified.
|
||||
|
@ -1368,13 +1368,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
|
||||
GenericBound::Trait(
|
||||
ty,
|
||||
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
|
||||
TraitBoundModifier::None
|
||||
| TraitBoundModifier::MaybeConst
|
||||
| TraitBoundModifier::Negative,
|
||||
) => Some(this.lower_poly_trait_ref(ty, itctx)),
|
||||
// `~const ?Bound` will cause an error during AST validation
|
||||
// anyways, so treat it like `?Bound` as compilation proceeds.
|
||||
GenericBound::Trait(
|
||||
_,
|
||||
TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe,
|
||||
TraitBoundModifier::Maybe
|
||||
| TraitBoundModifier::MaybeConstMaybe
|
||||
| TraitBoundModifier::MaybeConstNegative,
|
||||
) => None,
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
@ -2421,11 +2425,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
TraitBoundModifier::None => hir::TraitBoundModifier::None,
|
||||
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
|
||||
// placeholder for compilation to proceed.
|
||||
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
|
||||
hir::TraitBoundModifier::Maybe
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here
|
||||
.closure = closures 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`
|
||||
.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
|
||||
|
||||
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
|
||||
|
@ -1168,12 +1168,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
});
|
||||
}
|
||||
(_, 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)
|
||||
}
|
||||
|
||||
|
@ -567,6 +567,7 @@ pub enum TildeConstReason {
|
||||
pub struct OptionalConstExclusive {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub modifier: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -693,3 +694,17 @@ pub struct ShowSpan {
|
||||
pub span: Span,
|
||||
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,
|
||||
}
|
||||
|
@ -603,6 +603,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(dyn_star, "`dyn*` trait objects 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,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
// We emit an early future-incompatible warning for these.
|
||||
|
@ -1570,12 +1570,19 @@ impl<'a> State<'a> {
|
||||
GenericBound::Trait(tref, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => {}
|
||||
TraitBoundModifier::Negative => {
|
||||
self.word("!");
|
||||
}
|
||||
TraitBoundModifier::Maybe => {
|
||||
self.word("?");
|
||||
}
|
||||
TraitBoundModifier::MaybeConst => {
|
||||
self.word_space("~const");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => {
|
||||
self.word_space("~const");
|
||||
self.word("!");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstMaybe => {
|
||||
self.word_space("~const");
|
||||
self.word("?");
|
||||
|
@ -31,7 +31,7 @@ use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
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_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
|
||||
use rustc_session::cstore::{self, CrateSource};
|
||||
@ -39,6 +39,7 @@ use rustc_session::utils::NativeLibKind;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::DebuggerVisualizerFile;
|
||||
use std::collections::BTreeSet;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod back;
|
||||
@ -215,8 +216,11 @@ const RLINK_MAGIC: &[u8] = b"rustlink";
|
||||
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
|
||||
|
||||
impl CodegenResults {
|
||||
pub fn serialize_rlink(codegen_results: &CodegenResults) -> Vec<u8> {
|
||||
let mut encoder = MemEncoder::new();
|
||||
pub fn serialize_rlink(
|
||||
rlink_file: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut encoder = FileEncoder::new(rlink_file)?;
|
||||
encoder.emit_raw_bytes(RLINK_MAGIC);
|
||||
// `emit_raw_bytes` is used to make sure that the version representation does not depend on
|
||||
// Encoder's inner representation of `u32`.
|
||||
|
@ -337,7 +337,7 @@ fn valtree_into_mplace<'tcx>(
|
||||
|
||||
match ty.kind() {
|
||||
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 => {
|
||||
let scalar_int = valtree.unwrap_leaf();
|
||||
|
@ -245,6 +245,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
||||
impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
|
||||
pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
|
||||
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.
|
||||
self.assert_mem_place().len(cx)
|
||||
} else {
|
||||
|
@ -164,6 +164,8 @@ declare_features! (
|
||||
(active, link_cfg, "1.14.0", None, None),
|
||||
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||
(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]`.
|
||||
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
|
||||
/// Allows using `#[prelude_import]` on glob `use` items.
|
||||
|
@ -435,6 +435,7 @@ pub enum GenericArgsParentheses {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
Negative,
|
||||
Maybe,
|
||||
MaybeConst,
|
||||
}
|
||||
|
@ -665,6 +665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
span: Span,
|
||||
binding_span: Option<Span>,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
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);
|
||||
|
||||
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();
|
||||
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.
|
||||
let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
|
||||
hir_id,
|
||||
@ -711,6 +722,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
binding_span.unwrap_or(binding.span),
|
||||
constness,
|
||||
only_self_bounds,
|
||||
polarity,
|
||||
);
|
||||
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
|
||||
}
|
||||
@ -743,6 +755,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
@ -764,6 +777,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
span,
|
||||
binding_span,
|
||||
constness,
|
||||
polarity,
|
||||
bounds,
|
||||
speculative,
|
||||
trait_ref_span,
|
||||
@ -799,6 +813,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
span,
|
||||
binding_span,
|
||||
constness,
|
||||
ty::ImplPolarity::Positive,
|
||||
bounds,
|
||||
speculative,
|
||||
trait_ref_span,
|
||||
@ -961,16 +976,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
for ast_bound in ast_bounds {
|
||||
match ast_bound {
|
||||
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
|
||||
let constness = match modifier {
|
||||
hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
|
||||
hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
|
||||
let (constness, polarity) = match modifier {
|
||||
hir::TraitBoundModifier::MaybeConst => {
|
||||
(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,
|
||||
};
|
||||
|
||||
let _ = self.instantiate_poly_trait_ref(
|
||||
&poly_trait_ref.trait_ref,
|
||||
poly_trait_ref.span,
|
||||
constness,
|
||||
polarity,
|
||||
param_ty,
|
||||
bounds,
|
||||
false,
|
||||
@ -1088,6 +1110,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
path_span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
// Given something like `U: SomeTrait<T = X>`, we want to produce a
|
||||
// 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.span,
|
||||
ty::BoundConstness::NotConst,
|
||||
ty::ImplPolarity::Positive,
|
||||
dummy_self,
|
||||
&mut bounds,
|
||||
false,
|
||||
|
@ -42,8 +42,14 @@ impl<'tcx> Bounds<'tcx> {
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
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(
|
||||
|
@ -528,6 +528,7 @@ pub fn hir_trait_to_predicates<'tcx>(
|
||||
hir_trait,
|
||||
DUMMY_SP,
|
||||
ty::BoundConstness::NotConst,
|
||||
ty::ImplPolarity::Positive,
|
||||
self_ty,
|
||||
&mut bounds,
|
||||
true,
|
||||
|
@ -2822,7 +2822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// but has nested obligations which are unsatisfied.
|
||||
for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() {
|
||||
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);
|
||||
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.
|
||||
fn find_and_report_unsatisfied_index_impl(
|
||||
&self,
|
||||
index_expr_hir_id: HirId,
|
||||
base_expr: &hir::Expr<'_>,
|
||||
base_ty: Ty<'tcx>,
|
||||
) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> {
|
||||
@ -2914,13 +2913,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// in the first place.
|
||||
ocx.register_obligations(traits::predicates_for_generics(
|
||||
|idx, span| {
|
||||
traits::ObligationCause::new(
|
||||
base_expr.span,
|
||||
self.body_id,
|
||||
if span.is_dummy() {
|
||||
traits::ExprItemObligation(impl_def_id, index_expr_hir_id, idx)
|
||||
} else {
|
||||
traits::ExprBindingObligation(impl_def_id, span, index_expr_hir_id, idx)
|
||||
cause.clone().derived_cause(
|
||||
ty::Binder::dummy(ty::TraitPredicate {
|
||||
trait_ref: impl_trait_ref,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
}),
|
||||
|derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_or_alias_def_id: impl_def_id,
|
||||
impl_def_predicate_index: Some(idx),
|
||||
span,
|
||||
},
|
||||
))
|
||||
},
|
||||
)
|
||||
},
|
||||
|
@ -200,6 +200,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
||||
let bound_predicate = elaboratable.predicate().kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
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.
|
||||
let predicates = if self.only_self {
|
||||
tcx.super_predicates_of(data.def_id())
|
||||
|
@ -368,9 +368,8 @@ impl Linker {
|
||||
}
|
||||
|
||||
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);
|
||||
std::fs::write(&rlink_file, encoded)
|
||||
CodegenResults::serialize_rlink(&rlink_file, &codegen_results)
|
||||
.map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1364,9 +1364,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
record!(self.tables.params_in_repr[def_id] <- params_in_repr);
|
||||
|
||||
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] <-
|
||||
module_children.iter().map(|def_id| def_id.local_def_index));
|
||||
module_children.iter().map(|child| child.res.def_id().index));
|
||||
} else {
|
||||
// For non-enum, there is only one variant, and its def_id is the adt's.
|
||||
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.
|
||||
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
|
||||
} 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] <-
|
||||
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] <-
|
||||
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(..) => {
|
||||
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] <-
|
||||
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);
|
||||
record_associated_item_def_ids(self, associated_item_def_ids);
|
||||
|
@ -357,10 +357,16 @@ define_tables! {
|
||||
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
|
||||
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
|
||||
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>>,
|
||||
|
||||
- optional:
|
||||
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>>,
|
||||
associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
opt_def_kind: Table<DefIndex, DefKind>,
|
||||
|
@ -32,6 +32,9 @@ middle_values_too_big =
|
||||
middle_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 =
|
||||
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||
.label = due to this attribute
|
||||
|
@ -134,6 +134,9 @@ pub enum InvalidProgramInfo<'tcx> {
|
||||
FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
|
||||
/// SizeOf of unsized type was requested.
|
||||
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<'_> {
|
||||
@ -150,6 +153,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
|
||||
Layout(ref err) => write!(f, "{err}"),
|
||||
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
|
||||
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
|
||||
UninitUnsizedLocal => write!(f, "unsized local is used while uninitialized"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2414,26 +2414,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Named module children from all items except `use` and `extern crate` imports.
|
||||
///
|
||||
/// In addition to regular items this list also includes struct or variant constructors, and
|
||||
/// Named module children from all kinds of items, including imports.
|
||||
/// In addition to regular items this list also includes struct and variant constructors, and
|
||||
/// 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,
|
||||
/// 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,
|
||||
/// e.g. a glob import can introduce a lot of names, all with the same `DefId`.
|
||||
/// That's why the list needs to contain `ModChild` structures describing all the names
|
||||
/// individually instead of `DefId`s.
|
||||
pub fn module_children_reexports(self, def_id: LocalDefId) -> &'tcx [ModChild] {
|
||||
self.resolutions(()).module_children_reexports.get(&def_id).map_or(&[], |v| &v[..])
|
||||
/// This is not a query, making it a query causes perf regressions
|
||||
/// (probably due to hashing spans in `ModChild`ren).
|
||||
pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] {
|
||||
self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,6 +210,7 @@ pub enum LayoutError<'tcx> {
|
||||
Unknown(Ty<'tcx>),
|
||||
SizeOverflow(Ty<'tcx>),
|
||||
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
|
||||
Cycle,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_, !> for LayoutError<'_> {
|
||||
@ -230,6 +231,9 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
|
||||
diag.set_arg("failure_ty", e.get_type_for_failure());
|
||||
diag.set_primary_message(fluent::middle_cannot_be_normalized);
|
||||
}
|
||||
LayoutError::Cycle => {
|
||||
diag.set_primary_message(fluent::middle_cycle);
|
||||
}
|
||||
}
|
||||
diag
|
||||
}
|
||||
@ -250,6 +254,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
||||
t,
|
||||
e.get_type_for_failure()
|
||||
),
|
||||
LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,8 +165,7 @@ pub struct ResolverGlobalCtxt {
|
||||
pub effective_visibilities: EffectiveVisibilities,
|
||||
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||||
pub module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>,
|
||||
pub module_children_reexports: LocalDefIdMap<Vec<ModChild>>,
|
||||
pub module_children: LocalDefIdMap<Vec<ModChild>>,
|
||||
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||
pub main_def: Option<MainDefinition>,
|
||||
pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
|
||||
|
@ -2816,6 +2816,9 @@ define_print_and_forward_display! {
|
||||
if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
|
||||
p!("~const ");
|
||||
}
|
||||
if let ty::ImplPolarity::Negative = self.polarity {
|
||||
p!("!");
|
||||
}
|
||||
p!(print(self.trait_ref.print_only_trait_path()))
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
// type in the next element in the list
|
||||
pub fn recursive_type_error(
|
||||
|
@ -615,13 +615,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
|
||||
.help = `dyn` is only needed at the start of a trait `+`-separated list
|
||||
.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_standalone = pass `--edition {$edition}` to `rustc`
|
||||
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_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
|
||||
.suggestion = remove the parentheses
|
||||
|
@ -2280,31 +2280,6 @@ pub(crate) struct InvalidDynKeyword {
|
||||
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)]
|
||||
pub enum HelpUseLatestEdition {
|
||||
#[help(parse_help_set_edition_cargo)]
|
||||
@ -2412,10 +2387,12 @@ pub(crate) struct TildeConstLifetime {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_maybe_lifetime)]
|
||||
pub(crate) struct MaybeLifetime {
|
||||
#[diag(parse_modifier_lifetime)]
|
||||
pub(crate) struct ModifierLifetime {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
|
||||
pub span: Span,
|
||||
pub sigil: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -1284,7 +1284,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
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 sub = match &ty.kind {
|
||||
|
@ -78,7 +78,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
self.parse_generic_bounds(colon_span)?
|
||||
self.parse_generic_bounds()?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
@ -419,7 +419,7 @@ impl<'a> Parser<'a> {
|
||||
// or with mandatory equality sign and the second type.
|
||||
let ty = self.parse_ty_for_where_clause()?;
|
||||
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 {
|
||||
span: lo.to(self.prev_token.span),
|
||||
bound_generic_params: lifetime_defs,
|
||||
|
@ -788,11 +788,7 @@ impl<'a> Parser<'a> {
|
||||
// Parse optional colon and supertrait bounds.
|
||||
let had_colon = self.eat(&token::Colon);
|
||||
let span_at_colon = self.prev_token.span;
|
||||
let bounds = if had_colon {
|
||||
self.parse_generic_bounds(Some(self.prev_token.span))?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
|
||||
|
||||
let span_before_eq = self.prev_token.span;
|
||||
if self.eat(&token::Eq) {
|
||||
@ -802,7 +798,7 @@ impl<'a> Parser<'a> {
|
||||
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()?;
|
||||
self.expect_semi()?;
|
||||
|
||||
@ -883,7 +879,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// Parse optional colon and param 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 ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
|
||||
|
@ -606,7 +606,7 @@ impl<'a> Parser<'a> {
|
||||
let kind = if self.eat(&token::Colon) {
|
||||
// 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 }
|
||||
} else if self.eat(&token::Eq) {
|
||||
self.parse_assoc_equality_term(ident, self.prev_token.span)?
|
||||
|
@ -3,8 +3,7 @@ use super::{Parser, PathStyle, TokenType};
|
||||
use crate::errors::{
|
||||
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
|
||||
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
|
||||
InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
|
||||
NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
|
||||
InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
|
||||
ReturnTypesUseThinArrow,
|
||||
};
|
||||
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::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
|
||||
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
|
||||
self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam,
|
||||
Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier,
|
||||
TraitObjectSyntax, Ty, TyKind,
|
||||
};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_span::source_map::Span;
|
||||
@ -23,10 +23,10 @@ use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Symbol;
|
||||
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 {
|
||||
/// `?Trait`.
|
||||
maybe: Option<Span>,
|
||||
bound_polarity: BoundPolarity,
|
||||
|
||||
/// `~const Trait`.
|
||||
maybe_const: Option<Span>,
|
||||
@ -34,11 +34,13 @@ struct BoundModifiers {
|
||||
|
||||
impl BoundModifiers {
|
||||
fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
|
||||
match (self.maybe, self.maybe_const) {
|
||||
(None, None) => TraitBoundModifier::None,
|
||||
(Some(_), None) => TraitBoundModifier::Maybe,
|
||||
(None, Some(_)) => TraitBoundModifier::MaybeConst,
|
||||
(Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
|
||||
match (self.bound_polarity, self.maybe_const) {
|
||||
(BoundPolarity::Positive, None) => TraitBoundModifier::None,
|
||||
(BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative,
|
||||
(BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe,
|
||||
(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> {
|
||||
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 {
|
||||
self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
|
||||
}
|
||||
@ -395,7 +397,7 @@ impl<'a> Parser<'a> {
|
||||
) -> PResult<'a, TyKind> {
|
||||
if plus {
|
||||
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))
|
||||
}
|
||||
@ -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);
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
|
||||
}
|
||||
@ -629,7 +631,7 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
|
||||
// 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);
|
||||
Ok(TyKind::TraitObject(bounds, syntax))
|
||||
}
|
||||
@ -660,23 +662,15 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse_generic_bounds(
|
||||
&mut self,
|
||||
colon_span: Option<Span>,
|
||||
) -> PResult<'a, GenericBounds> {
|
||||
self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
|
||||
pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
|
||||
self.parse_generic_bounds_common(AllowPlus::Yes)
|
||||
}
|
||||
|
||||
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
|
||||
///
|
||||
/// See `parse_generic_bound` for the `BOUND` grammar.
|
||||
fn parse_generic_bounds_common(
|
||||
&mut self,
|
||||
allow_plus: AllowPlus,
|
||||
colon_span: Option<Span>,
|
||||
) -> PResult<'a, GenericBounds> {
|
||||
fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
|
||||
let mut bounds = Vec::new();
|
||||
let mut negative_bounds = Vec::new();
|
||||
|
||||
// In addition to looping while we find generic bounds:
|
||||
// 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.bump();
|
||||
}
|
||||
match self.parse_generic_bound()? {
|
||||
Ok(bound) => bounds.push(bound),
|
||||
Err(neg_sp) => negative_bounds.push(neg_sp),
|
||||
}
|
||||
bounds.push(self.parse_generic_bound()?);
|
||||
if allow_plus == AllowPlus::No || !self.eat_plus() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !negative_bounds.is_empty() {
|
||||
self.error_negative_bounds(colon_span, &bounds, negative_bounds);
|
||||
}
|
||||
|
||||
Ok(bounds)
|
||||
}
|
||||
|
||||
@ -713,55 +700,22 @@ impl<'a> Parser<'a> {
|
||||
fn can_begin_bound(&mut self) -> bool {
|
||||
// This needs to be synchronized with `TokenKind::can_begin_bound`.
|
||||
self.check_path()
|
||||
|| self.check_lifetime()
|
||||
|| self.check(&token::Not) // Used for error reporting only.
|
||||
|| self.check(&token::Question)
|
||||
|| self.check(&token::Tilde)
|
||||
|| self.check_keyword(kw::For)
|
||||
|| 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 });
|
||||
|| self.check_lifetime()
|
||||
|| self.check(&token::Not)
|
||||
|| self.check(&token::Question)
|
||||
|| self.check(&token::Tilde)
|
||||
|| self.check_keyword(kw::For)
|
||||
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
|
||||
}
|
||||
|
||||
/// Parses a bound according to the grammar:
|
||||
/// ```ebnf
|
||||
/// BOUND = TY_BOUND | LT_BOUND
|
||||
/// ```
|
||||
fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
|
||||
let anchor_lo = self.prev_token.span;
|
||||
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
|
||||
let lo = self.token.span;
|
||||
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
|
||||
let inner_lo = self.token.span;
|
||||
let is_negative = self.eat(&token::Not);
|
||||
|
||||
let modifiers = self.parse_ty_bound_modifiers()?;
|
||||
let bound = if self.token.is_lifetime() {
|
||||
@ -771,7 +725,7 @@ impl<'a> Parser<'a> {
|
||||
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:
|
||||
@ -799,8 +753,14 @@ impl<'a> Parser<'a> {
|
||||
self.sess.emit_err(errors::TildeConstLifetime { span });
|
||||
}
|
||||
|
||||
if let Some(span) = modifiers.maybe {
|
||||
self.sess.emit_err(errors::MaybeLifetime { span });
|
||||
match modifiers.bound_polarity {
|
||||
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
|
||||
};
|
||||
|
||||
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:
|
||||
|
@ -101,12 +101,11 @@ impl CheckAttrVisitor<'_> {
|
||||
item: Option<ItemLike<'_>>,
|
||||
) {
|
||||
let mut doc_aliases = FxHashMap::default();
|
||||
let mut is_valid = true;
|
||||
let mut specified_inline = None;
|
||||
let mut seen = FxHashMap::default();
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
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::inline => self.check_inline(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),
|
||||
_ => true,
|
||||
};
|
||||
is_valid &= attr_is_valid;
|
||||
|
||||
// lint-only checks
|
||||
match attr.name_or_empty() {
|
||||
@ -255,10 +253,6 @@ impl CheckAttrVisitor<'_> {
|
||||
self.check_unused_attribute(hir_id, attr)
|
||||
}
|
||||
|
||||
if !is_valid {
|
||||
return;
|
||||
}
|
||||
|
||||
self.check_repr(attrs, span, target, item, hir_id);
|
||||
self.check_used(attrs, target);
|
||||
}
|
||||
|
@ -515,9 +515,11 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
||||
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);
|
||||
}
|
||||
for export in self.tcx.module_children_reexports(module_def_id) {
|
||||
if export.vis.is_accessible_from(defining_mod, self.tcx)
|
||||
&& let Res::Def(def_kind, def_id) = export.res
|
||||
for child in self.tcx.module_children_local(module_def_id) {
|
||||
// FIXME: Use module children for the logic above too.
|
||||
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 vis = self.tcx.local_visibility(def_id);
|
||||
self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
|
||||
|
@ -1261,14 +1261,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
*module.globs.borrow_mut() = Vec::new();
|
||||
|
||||
if let Some(def_id) = module.opt_def_id() {
|
||||
let mut non_reexports = Vec::new();
|
||||
let mut reexports = Vec::new();
|
||||
let mut children = Vec::new();
|
||||
|
||||
module.for_each_child(self, |this, ident, _, binding| {
|
||||
let res = binding.res().expect_non_local();
|
||||
if !binding.is_import() {
|
||||
non_reexports.push(res.def_id().expect_local());
|
||||
} else if res != def::Res::Err && !binding.is_ambiguity() {
|
||||
if res != def::Res::Err && !binding.is_ambiguity() {
|
||||
let mut reexport_chain = SmallVec::new();
|
||||
let mut next_binding = binding;
|
||||
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
|
||||
@ -1276,17 +1273,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
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.
|
||||
let def_id = def_id.expect_local();
|
||||
if !non_reexports.is_empty() {
|
||||
self.module_children_non_reexports.insert(def_id, non_reexports);
|
||||
}
|
||||
if !reexports.is_empty() {
|
||||
self.module_children_reexports.insert(def_id, reexports);
|
||||
if !children.is_empty() {
|
||||
// Should be fine because this code is only called for local modules.
|
||||
self.module_children.insert(def_id.expect_local(), children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -909,8 +909,7 @@ pub struct Resolver<'a, 'tcx> {
|
||||
|
||||
/// `CrateNum` resolutions of `extern crate` items.
|
||||
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
|
||||
module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>,
|
||||
module_children_reexports: LocalDefIdMap<Vec<ModChild>>,
|
||||
module_children: LocalDefIdMap<Vec<ModChild>>,
|
||||
trait_map: NodeMap<Vec<TraitCandidate>>,
|
||||
|
||||
/// A map from nodes to anonymous modules.
|
||||
@ -1260,8 +1259,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
lifetimes_res_map: Default::default(),
|
||||
extra_lifetime_params_map: Default::default(),
|
||||
extern_crate_map: Default::default(),
|
||||
module_children_non_reexports: Default::default(),
|
||||
module_children_reexports: Default::default(),
|
||||
module_children: Default::default(),
|
||||
trait_map: NodeMap::default(),
|
||||
underscore_disambiguator: 0,
|
||||
empty_module,
|
||||
@ -1399,8 +1397,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
has_pub_restricted,
|
||||
effective_visibilities,
|
||||
extern_crate_map,
|
||||
module_children_non_reexports: self.module_children_non_reexports,
|
||||
module_children_reexports: self.module_children_reexports,
|
||||
module_children: self.module_children,
|
||||
glob_map,
|
||||
maybe_unused_trait_imports,
|
||||
main_def,
|
||||
|
@ -10,3 +10,4 @@ thin-vec = "0.2.12"
|
||||
|
||||
[dev-dependencies]
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
tempfile = "3.2"
|
||||
|
@ -12,118 +12,14 @@ use std::ptr;
|
||||
// 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>;
|
||||
|
||||
/// `FileEncoder` encodes data to file via fixed-size buffer.
|
||||
///
|
||||
/// When encoding large amounts of data to a file, using `FileEncoder` may be
|
||||
/// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the
|
||||
/// `Vec` to file, as the latter uses as much memory as there is encoded data,
|
||||
/// while the former uses the fixed amount of memory allocated to the buffer.
|
||||
/// `FileEncoder` also has the advantage of not needing to reallocate as data
|
||||
/// is appended to it, but the disadvantage of requiring more error handling,
|
||||
/// which has some runtime overhead.
|
||||
/// There used to be a `MemEncoder` type that encoded all the data into a
|
||||
/// `Vec`. `FileEncoder` is better because its memory use is determined by the
|
||||
/// size of the buffer, rather than the full length of the encoded data, and
|
||||
/// because it doesn't need to reallocate memory along the way.
|
||||
pub struct FileEncoder {
|
||||
/// The input buffer. For adequate performance, we need more control over
|
||||
/// 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.,
|
||||
// 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] {
|
||||
fn encode(&self, e: &mut FileEncoder) {
|
||||
Encoder::emit_usize(e, self.len());
|
||||
@ -675,16 +564,6 @@ impl IntEncodedWithFixedSize {
|
||||
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 {
|
||||
#[inline]
|
||||
fn encode(&self, e: &mut FileEncoder) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
#![allow(rustc::internal)]
|
||||
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
|
||||
use rustc_serialize::opaque::{MemDecoder, FileEncoder};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
|
||||
struct Struct {
|
||||
@ -27,18 +28,21 @@ struct Struct {
|
||||
}
|
||||
|
||||
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>,
|
||||
) {
|
||||
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 {
|
||||
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);
|
||||
|
||||
for value in values {
|
||||
let decoded = Decodable::decode(&mut decoder);
|
||||
assert_eq!(value, decoded);
|
||||
@ -61,7 +65,7 @@ fn test_u8() {
|
||||
|
||||
#[test]
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@ -92,7 +96,7 @@ fn test_i8() {
|
||||
|
||||
#[test]
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@ -251,3 +255,41 @@ fn test_tuples() {
|
||||
check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]);
|
||||
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]);
|
||||
}
|
||||
|
@ -984,6 +984,7 @@ symbols! {
|
||||
needs_panic_runtime,
|
||||
neg,
|
||||
negate_unsigned,
|
||||
negative_bounds,
|
||||
negative_impls,
|
||||
neon,
|
||||
never,
|
||||
|
@ -530,6 +530,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
associated_ty: Option<(&'static str, Ty<'tcx>)>,
|
||||
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 self_ty = trait_pred.skip_binder().self_ty();
|
||||
|
@ -57,6 +57,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
if obligation.polarity() == ty::ImplPolarity::Negative {
|
||||
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
|
||||
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
||||
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
|
||||
} else {
|
||||
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.
|
||||
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
|
||||
// polarity here.
|
||||
let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;
|
||||
|
@ -328,6 +328,13 @@ impl<'tcx> WfPredicates<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
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.
|
||||
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
|
||||
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
|
||||
/// into `self.out`.
|
||||
fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
|
@ -919,6 +919,7 @@ fn symlink_noexist() {
|
||||
|
||||
#[test]
|
||||
fn read_link() {
|
||||
let tmpdir = tmpdir();
|
||||
if cfg!(windows) {
|
||||
// directory symlink
|
||||
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")
|
||||
);
|
||||
}
|
||||
// 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");
|
||||
if !got_symlink_permission(&tmpdir) {
|
||||
return;
|
||||
|
@ -313,6 +313,9 @@ pub(crate) fn make_bat_command_line(
|
||||
///
|
||||
/// This is necessary because cmd.exe does not support verbatim paths.
|
||||
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::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 C: u16 = b'C' as _;
|
||||
|
||||
let mut path = to_u16s(path)?;
|
||||
|
||||
// Early return if the path is too long to remove the verbatim prefix.
|
||||
const LEGACY_MAX_PATH: usize = 260;
|
||||
if path.len() > LEGACY_MAX_PATH {
|
||||
|
@ -477,7 +477,7 @@ impl File {
|
||||
fn reparse_point(
|
||||
&self,
|
||||
space: &mut Align8<[MaybeUninit<u8>]>,
|
||||
) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> {
|
||||
) -> io::Result<(c::DWORD, *mut c::REPARSE_DATA_BUFFER)> {
|
||||
unsafe {
|
||||
let mut bytes = 0;
|
||||
cvt({
|
||||
@ -496,7 +496,7 @@ impl File {
|
||||
)
|
||||
})?;
|
||||
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 {
|
||||
let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
|
||||
c::IO_REPARSE_TAG_SYMLINK => {
|
||||
let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
|
||||
ptr::addr_of!((*buf).rest).cast();
|
||||
let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER =
|
||||
ptr::addr_of_mut!((*buf).rest).cast();
|
||||
assert!(info.is_aligned());
|
||||
(
|
||||
ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
|
||||
ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
|
||||
(*info).SubstituteNameOffset / 2,
|
||||
(*info).SubstituteNameLength / 2,
|
||||
(*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0,
|
||||
)
|
||||
}
|
||||
c::IO_REPARSE_TAG_MOUNT_POINT => {
|
||||
let info: *const c::MOUNT_POINT_REPARSE_BUFFER =
|
||||
ptr::addr_of!((*buf).rest).cast();
|
||||
let info: *mut c::MOUNT_POINT_REPARSE_BUFFER =
|
||||
ptr::addr_of_mut!((*buf).rest).cast();
|
||||
assert!(info.is_aligned());
|
||||
(
|
||||
ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
|
||||
ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
|
||||
(*info).SubstituteNameOffset / 2,
|
||||
(*info).SubstituteNameLength / 2,
|
||||
false,
|
||||
@ -535,13 +535,20 @@ impl File {
|
||||
}
|
||||
};
|
||||
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 `\??\`
|
||||
// We should not let it leak through.
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -427,7 +427,6 @@ impl Config {
|
||||
|
||||
fn download_toolchain(
|
||||
&self,
|
||||
// FIXME(ozkanonur) use CompilerMetadata instead of `version: &str`
|
||||
version: &str,
|
||||
sysroot: &str,
|
||||
stamp_key: &str,
|
||||
|
@ -152,8 +152,9 @@ pub(crate) fn try_inline_glob(
|
||||
// reexported by the glob, e.g. because they are shadowed by something else.
|
||||
let reexports = cx
|
||||
.tcx
|
||||
.module_children_reexports(current_mod)
|
||||
.module_children_local(current_mod)
|
||||
.iter()
|
||||
.filter(|child| !child.reexport_chain.is_empty())
|
||||
.filter_map(|child| child.res.opt_def_id())
|
||||
.collect();
|
||||
let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
|
||||
|
@ -2089,9 +2089,9 @@ pub(crate) fn reexport_chain<'tcx>(
|
||||
import_def_id: LocalDefId,
|
||||
target_def_id: LocalDefId,
|
||||
) -> &'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())
|
||||
&& 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;
|
||||
}
|
||||
|
@ -439,6 +439,7 @@ impl clean::GenericBound {
|
||||
let modifier_str = match modifier {
|
||||
hir::TraitBoundModifier::None => "",
|
||||
hir::TraitBoundModifier::Maybe => "?",
|
||||
hir::TraitBoundModifier::Negative => "!",
|
||||
// ~const is experimental; do not display those bounds in rustdoc
|
||||
hir::TraitBoundModifier::MaybeConst => "",
|
||||
};
|
||||
|
@ -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> {# #}
|
||||
</h2> {# #}
|
||||
<div class="docblock"> {# #}
|
||||
{% match type_layout_size %}
|
||||
{% when Ok(type_layout_size) %}
|
||||
<div class="warning"> {# #}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Most layout information is <strong>completely {#+ #}
|
||||
unstable</strong> and may even differ between compilations. {#+ #}
|
||||
The only exception is types with certain <code>repr(...)</code> {#+ #}
|
||||
attributes. Please see the Rust Reference’s {#+ #}
|
||||
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
|
||||
chapter for details on type layout guarantees. {# #}
|
||||
</p> {# #}
|
||||
</div> {# #}
|
||||
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
|
||||
{% if !variants.is_empty() %}
|
||||
<p> {# #}
|
||||
<strong>Size for each variant:</strong> {# #}
|
||||
</p> {# #}
|
||||
<ul> {# #}
|
||||
{% for (name, layout_size) in variants %}
|
||||
<li> {# #}
|
||||
<code>{{ name }}</code>: {#+ #}
|
||||
{{ layout_size|safe }}
|
||||
</li> {# #}
|
||||
{% endfor %}
|
||||
</ul> {# #}
|
||||
{% endif %}
|
||||
{# 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>`. #}
|
||||
{% when Ok(type_layout_size) %}
|
||||
<div class="warning"> {# #}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Most layout information is <strong>completely {#+ #}
|
||||
unstable</strong> and may even differ between compilations. {#+ #}
|
||||
The only exception is types with certain <code>repr(...)</code> {#+ #}
|
||||
attributes. Please see the Rust Reference’s {#+ #}
|
||||
<a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
|
||||
chapter for details on type layout guarantees. {# #}
|
||||
</p> {# #}
|
||||
</div> {# #}
|
||||
<p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
|
||||
{% if !variants.is_empty() %}
|
||||
<p> {# #}
|
||||
<strong>Size for each variant:</strong> {# #}
|
||||
</p> {# #}
|
||||
<ul> {# #}
|
||||
{% for (name, layout_size) in variants %}
|
||||
<li> {# #}
|
||||
<code>{{ name }}</code>: {#+ #}
|
||||
{{ layout_size|safe }}
|
||||
</li> {# #}
|
||||
{% endfor %}
|
||||
</ul> {# #}
|
||||
{% endif %}
|
||||
{# 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>`. #}
|
||||
{% when Err(LayoutError::Unknown(_)) %}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Unable to compute type layout, {#+ #}
|
||||
possibly due to this type having generic parameters. {#+ #}
|
||||
Layout can only be computed for concrete, fully-instantiated types. {# #}
|
||||
</p> {# #}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Unable to compute type layout, {#+ #}
|
||||
possibly due to this type having generic parameters. {#+ #}
|
||||
Layout can only be computed for concrete, fully-instantiated types. {# #}
|
||||
</p> {# #}
|
||||
{# 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
|
||||
user know that we couldn't compute the layout. #}
|
||||
want to panic and prevent the docs from building, so we just let the
|
||||
user know that we couldn't compute the layout. #}
|
||||
{% when Err(LayoutError::SizeOverflow(_)) %}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
|
||||
the type was too big. {# #}
|
||||
</p> {# #}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
|
||||
the type was too big. {# #}
|
||||
</p> {# #}
|
||||
{% when Err(LayoutError::NormalizationFailure(_, _)) %}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
|
||||
the type failed to be normalized. {# #}
|
||||
</p> {# #}
|
||||
{% endmatch %}
|
||||
<p> {# #}
|
||||
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
|
||||
the type failed to be normalized. {# #}
|
||||
</p> {# #}
|
||||
{% 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> {# #}
|
||||
|
@ -533,6 +533,10 @@ pub(crate) fn from_trait_bound_modifier(
|
||||
None => TraitBoundModifier::None,
|
||||
Maybe => TraitBoundModifier::Maybe,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,14 +136,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
// is declared but also a reexport of itself producing two exports of the same
|
||||
// macro in the same module.
|
||||
let mut inserted = FxHashSet::default();
|
||||
for export in self.cx.tcx.module_children_reexports(CRATE_DEF_ID) {
|
||||
if let Res::Def(DefKind::Macro(_), def_id) = export.res &&
|
||||
for child in self.cx.tcx.module_children_local(CRATE_DEF_ID) {
|
||||
if !child.reexport_chain.is_empty() &&
|
||||
let Res::Def(DefKind::Macro(_), def_id) = child.res &&
|
||||
let Some(local_def_id) = def_id.as_local() &&
|
||||
self.cx.tcx.has_attr(def_id, sym::macro_export) &&
|
||||
inserted.insert(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));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
anyhow = "1.0.32"
|
||||
flate2 = "1.0.16"
|
||||
xz2 = "0.1.7"
|
||||
tar = "0.4.29"
|
||||
sha2 = "0.10.1"
|
||||
rayon = "1.5.1"
|
||||
|
@ -5,6 +5,7 @@ use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tar::Archive;
|
||||
use xz2::read::XzDecoder;
|
||||
|
||||
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> {
|
||||
let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
|
||||
let tarball = self.dist_path.join(tarball_name);
|
||||
for ext in ["xz", "gz"] {
|
||||
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) {
|
||||
Ok(file) => file,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
@ -187,7 +202,14 @@ impl Versions {
|
||||
}
|
||||
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 git_commit = None;
|
||||
|
28
src/tools/miri/tests/fail/layout_cycle.rs
Normal file
28
src/tools/miri/tests/fail/layout_cycle.rs
Normal 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<()>>());
|
||||
}
|
28
src/tools/miri/tests/fail/layout_cycle.stderr
Normal file
28
src/tools/miri/tests/fail/layout_cycle.stderr
Normal 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`.
|
@ -552,6 +552,12 @@ impl Rewrite for ast::GenericBound {
|
||||
ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
|
||||
.rewrite(context, shape.offset_left(8)?)
|
||||
.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 })
|
||||
}
|
||||
|
11
src/tools/rustfmt/tests/target/negative-bounds.rs
Normal file
11
src/tools/rustfmt/tests/target/negative-bounds.rs
Normal file
@ -0,0 +1,11 @@
|
||||
fn negative()
|
||||
where
|
||||
i32: !Copy,
|
||||
{
|
||||
}
|
||||
|
||||
fn maybe_const_negative()
|
||||
where
|
||||
i32: ~const !Copy,
|
||||
{
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
9
tests/ui/const_prop/unsized-local-ice.rs
Normal file
9
tests/ui/const_prop/unsized-local-ice.rs
Normal 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() {}
|
4
tests/ui/feature-gates/feature-gate-negative_bounds.rs
Normal file
4
tests/ui/feature-gates/feature-gate-negative_bounds.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn test<T: !Copy>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
|
||||
fn main() {}
|
@ -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
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-58857.rs:4:7
|
||||
--> $DIR/issue-58857.rs:4:9
|
||||
|
|
||||
LL | impl<A: !Valid> Conj<A>{}
|
||||
| ^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -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() {}
|
@ -1,5 +1,3 @@
|
||||
// run-rustfix
|
||||
|
||||
trait Tr: !SuperA {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr2: SuperA + !SuperB {}
|
||||
@ -7,10 +5,12 @@ trait Tr2: SuperA + !SuperB {}
|
||||
trait Tr3: !SuperA + SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr4: !SuperA + SuperB
|
||||
+ !SuperC + SuperD {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
+ !SuperC + SuperD {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr5: !SuperA
|
||||
+ !SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
+ !SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
|
||||
trait SuperA {}
|
||||
|
@ -1,36 +1,44 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:3:9
|
||||
--> $DIR/issue-33418.rs:1:11
|
||||
|
|
||||
LL | trait Tr: !SuperA {}
|
||||
| ^^^^^^^^^ 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 {}
|
||||
| ^^^^^^^^^ 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 {}
|
||||
| ^^^^^^^^^ 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 | + !SuperC + SuperD {}
|
||||
| ^^^^^^^^^ 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 | + !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
|
||||
|
||||
|
@ -6,9 +6,12 @@
|
||||
|
||||
fn main() {}
|
||||
|
||||
pub fn f1<T>() {}
|
||||
pub fn f1<T: 'static>() {}
|
||||
//~^ 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
|
||||
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 `!` may only modify trait bounds, not lifetime bound
|
||||
|
@ -8,7 +8,10 @@ fn main() {}
|
||||
|
||||
pub fn f1<T: !'static>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
pub fn f2<'a, T: Ord + !'a>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
pub fn f3<'a, T: !'a + Ord>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
|
@ -1,20 +1,38 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:12
|
||||
error: `!` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:14
|
||||
|
|
||||
LL | pub fn f1<T: !'static>() {}
|
||||
| ^^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:22
|
||||
error: `!` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:12:24
|
||||
|
|
||||
LL | pub fn f2<'a, T: Ord + !'a>() {}
|
||||
| ^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:13:16
|
||||
error: `!` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:15:18
|
||||
|
|
||||
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
|
||||
|
||||
|
@ -15,3 +15,8 @@ pub struct OwO3 {
|
||||
pub enum OwO4 {
|
||||
UwU = 1,
|
||||
}
|
||||
|
||||
#[repr(uwu)] //~ERROR: unrecognized representation hint
|
||||
#[doc(owo)] //~WARN: unknown `doc` attribute
|
||||
//~^ WARN: this was previously
|
||||
pub struct Owo5;
|
||||
|
@ -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`
|
||||
|
||||
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`.
|
||||
|
20
tests/ui/traits/negative-bounds/associated-constraints.rs
Normal file
20
tests/ui/traits/negative-bounds/associated-constraints.rs
Normal 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() {}
|
@ -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
|
||||
|
42
tests/ui/traits/negative-bounds/simple.rs
Normal file
42
tests/ui/traits/negative-bounds/simple.rs
Normal 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() {}
|
70
tests/ui/traits/negative-bounds/simple.stderr
Normal file
70
tests/ui/traits/negative-bounds/simple.stderr
Normal 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`.
|
@ -4,11 +4,14 @@ error[E0277]: the trait bound `K: Hash` is not satisfied
|
||||
LL | map[k]
|
||||
| ^^^ the trait `Hash` is not implemented for `K`
|
||||
|
|
||||
note: required by a bound in `<HashMap<K, V> as Index<&K>>`
|
||||
--> $DIR/bad-index-due-to-nested.rs:9:8
|
||||
note: required for `HashMap<K, V>` to implement `Index<&K>`
|
||||
--> $DIR/bad-index-due-to-nested.rs:7:12
|
||||
|
|
||||
LL | impl<K, V> Index<&K> for HashMap<K, V>
|
||||
| ^^^^^^^^^ ^^^^^^^^^^^^^
|
||||
LL | where
|
||||
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`
|
||||
|
|
||||
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]
|
||||
| ^^^ the trait `Copy` is not implemented for `V`
|
||||
|
|
||||
note: required by a bound in `<HashMap<K, V> as Index<&K>>`
|
||||
--> $DIR/bad-index-due-to-nested.rs:10:8
|
||||
note: required for `HashMap<K, V>` to implement `Index<&K>`
|
||||
--> $DIR/bad-index-due-to-nested.rs:7:12
|
||||
|
|
||||
LL | impl<K, V> Index<&K> for HashMap<K, V>
|
||||
| ^^^^^^^^^ ^^^^^^^^^^^^^
|
||||
...
|
||||
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`
|
||||
|
|
||||
LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V {
|
||||
|
@ -475,10 +475,10 @@ cc = ["@rust-lang/style"]
|
||||
|
||||
[mentions."Cargo.lock"]
|
||||
message = """
|
||||
These commits modify the `Cargo.lock` file. Random 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.
|
||||
These commits modify the `Cargo.lock` file. Unintentional changes to `Cargo.lock` can be introduced when switching branches and rebasing PRs.
|
||||
|
||||
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"]
|
||||
@ -489,6 +489,14 @@ message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appro
|
||||
[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."
|
||||
|
||||
[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]
|
||||
warn_non_default_branch = true
|
||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||
|
Loading…
x
Reference in New Issue
Block a user