Auto merge of #139269 - matthiaskrgr:rollup-pk78gig, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #138992 (literal pattern lowering: use the pattern's type instead of the literal's in `const_to_pat`) - #139211 (interpret: add a version of run_for_validation for &self) - #139235 (`AstValidator` tweaks) - #139237 (Add a dep kind for use of the anon node with zero dependencies) - #139260 (Add dianqk to codegen reviewers) - #139264 (Fix two incorrect turbofish suggestions) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d5b4c2e4f1
22 changed files with 477 additions and 264 deletions
|
@ -47,14 +47,14 @@ enum SelfSemantic {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TraitOrTraitImpl {
|
enum TraitOrTraitImpl {
|
||||||
Trait { span: Span, constness: Option<Span> },
|
Trait { span: Span, constness_span: Option<Span> },
|
||||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: Span },
|
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TraitOrTraitImpl {
|
impl TraitOrTraitImpl {
|
||||||
fn constness(&self) -> Option<Span> {
|
fn constness(&self) -> Option<Span> {
|
||||||
match self {
|
match self {
|
||||||
Self::Trait { constness: Some(span), .. }
|
Self::Trait { constness_span: Some(span), .. }
|
||||||
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
|
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ struct AstValidator<'a> {
|
||||||
features: &'a Features,
|
features: &'a Features,
|
||||||
|
|
||||||
/// The span of the `extern` in an `extern { ... }` block, if any.
|
/// The span of the `extern` in an `extern { ... }` block, if any.
|
||||||
extern_mod: Option<Span>,
|
extern_mod_span: Option<Span>,
|
||||||
|
|
||||||
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
|
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ struct AstValidator<'a> {
|
||||||
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
|
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
|
||||||
/// Nested `impl Trait` _is_ allowed in associated type position,
|
/// Nested `impl Trait` _is_ allowed in associated type position,
|
||||||
/// e.g., `impl Iterator<Item = impl Debug>`.
|
/// e.g., `impl Iterator<Item = impl Debug>`.
|
||||||
outer_impl_trait: Option<Span>,
|
outer_impl_trait_span: Option<Span>,
|
||||||
|
|
||||||
disallow_tilde_const: Option<TildeConstReason>,
|
disallow_tilde_const: Option<TildeConstReason>,
|
||||||
|
|
||||||
|
@ -96,17 +96,22 @@ impl<'a> AstValidator<'a> {
|
||||||
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
||||||
constness,
|
constness,
|
||||||
polarity,
|
polarity,
|
||||||
trait_ref: trait_ref.path.span,
|
trait_ref_span: trait_ref.path.span,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
f(self);
|
f(self);
|
||||||
self.outer_trait_or_trait_impl = old;
|
self.outer_trait_or_trait_impl = old;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) {
|
fn with_in_trait(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
constness_span: Option<Span>,
|
||||||
|
f: impl FnOnce(&mut Self),
|
||||||
|
) {
|
||||||
let old = mem::replace(
|
let old = mem::replace(
|
||||||
&mut self.outer_trait_or_trait_impl,
|
&mut self.outer_trait_or_trait_impl,
|
||||||
Some(TraitOrTraitImpl::Trait { span, constness }),
|
Some(TraitOrTraitImpl::Trait { span, constness_span }),
|
||||||
);
|
);
|
||||||
f(self);
|
f(self);
|
||||||
self.outer_trait_or_trait_impl = old;
|
self.outer_trait_or_trait_impl = old;
|
||||||
|
@ -170,10 +175,10 @@ impl<'a> AstValidator<'a> {
|
||||||
Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
|
Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
|
fn with_impl_trait(&mut self, outer_span: Option<Span>, f: impl FnOnce(&mut Self)) {
|
||||||
let old = mem::replace(&mut self.outer_impl_trait, outer);
|
let old = mem::replace(&mut self.outer_impl_trait_span, outer_span);
|
||||||
f(self);
|
f(self);
|
||||||
self.outer_impl_trait = old;
|
self.outer_impl_trait_span = old;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
||||||
|
@ -258,21 +263,22 @@ impl<'a> AstValidator<'a> {
|
||||||
&& let TraitOrTraitImpl::TraitImpl {
|
&& let TraitOrTraitImpl::TraitImpl {
|
||||||
constness: Const::No,
|
constness: Const::No,
|
||||||
polarity: ImplPolarity::Positive,
|
polarity: ImplPolarity::Positive,
|
||||||
trait_ref,
|
trait_ref_span,
|
||||||
..
|
..
|
||||||
} = parent
|
} = parent
|
||||||
{
|
{
|
||||||
Some(trait_ref.shrink_to_lo())
|
Some(trait_ref_span.shrink_to_lo())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let make_trait_const_sugg =
|
let make_trait_const_sugg = if const_trait_impl
|
||||||
if const_trait_impl && let TraitOrTraitImpl::Trait { span, constness: None } = parent {
|
&& let TraitOrTraitImpl::Trait { span, constness_span: None } = parent
|
||||||
Some(span.shrink_to_lo())
|
{
|
||||||
} else {
|
Some(span.shrink_to_lo())
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let parent_constness = parent.constness();
|
let parent_constness = parent.constness();
|
||||||
self.dcx().emit_err(errors::TraitFnConst {
|
self.dcx().emit_err(errors::TraitFnConst {
|
||||||
|
@ -448,13 +454,13 @@ impl<'a> AstValidator<'a> {
|
||||||
check_where_clause(where_clauses.after);
|
check_where_clause(where_clauses.after);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
|
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body_span: Option<Span>) {
|
||||||
let Some(body) = body else {
|
let Some(body_span) = body_span else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.dcx().emit_err(errors::BodyInExtern {
|
self.dcx().emit_err(errors::BodyInExtern {
|
||||||
span: ident.span,
|
span: ident.span,
|
||||||
body,
|
body: body_span,
|
||||||
block: self.current_extern_span(),
|
block: self.current_extern_span(),
|
||||||
kind,
|
kind,
|
||||||
});
|
});
|
||||||
|
@ -473,7 +479,7 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_extern_span(&self) -> Span {
|
fn current_extern_span(&self) -> Span {
|
||||||
self.sess.source_map().guess_head_span(self.extern_mod.unwrap())
|
self.sess.source_map().guess_head_span(self.extern_mod_span.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
|
/// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
|
||||||
|
@ -583,9 +589,10 @@ impl<'a> AstValidator<'a> {
|
||||||
self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
|
self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deny_generic_params(&self, generics: &Generics, ident: Span) {
|
fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
|
||||||
if !generics.params.is_empty() {
|
if !generics.params.is_empty() {
|
||||||
self.dcx().emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
|
self.dcx()
|
||||||
|
.emit_err(errors::AutoTraitGeneric { span: generics.span, ident: ident_span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,11 +612,11 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deny_items(&self, trait_items: &[P<AssocItem>], ident: Span) {
|
fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
|
||||||
if !trait_items.is_empty() {
|
if !trait_items.is_empty() {
|
||||||
let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();
|
let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();
|
||||||
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
|
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
|
||||||
self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident });
|
self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident: ident_span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +701,7 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyKind::ImplTrait(_, bounds) => {
|
TyKind::ImplTrait(_, bounds) => {
|
||||||
if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
|
if let Some(outer_impl_trait_sp) = self.outer_impl_trait_span {
|
||||||
self.dcx().emit_err(errors::NestedImplTrait {
|
self.dcx().emit_err(errors::NestedImplTrait {
|
||||||
span: ty.span,
|
span: ty.span,
|
||||||
outer: outer_impl_trait_sp,
|
outer: outer_impl_trait_sp,
|
||||||
|
@ -727,6 +734,19 @@ impl<'a> AstValidator<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
|
||||||
|
fn visit_attrs_vis(&mut self, attrs: &'a AttrVec, vis: &'a Visibility) {
|
||||||
|
walk_list!(self, visit_attribute, attrs);
|
||||||
|
self.visit_vis(vis);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
|
||||||
|
fn visit_attrs_vis_ident(&mut self, attrs: &'a AttrVec, vis: &'a Visibility, ident: &'a Ident) {
|
||||||
|
walk_list!(self, visit_attribute, attrs);
|
||||||
|
self.visit_vis(vis);
|
||||||
|
self.visit_ident(ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that generic parameters are in the correct order,
|
/// Checks that generic parameters are in the correct order,
|
||||||
|
@ -834,36 +854,33 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self_ty,
|
self_ty,
|
||||||
items,
|
items,
|
||||||
}) => {
|
}) => {
|
||||||
|
self.visit_attrs_vis(&item.attrs, &item.vis);
|
||||||
|
self.visibility_not_permitted(
|
||||||
|
&item.vis,
|
||||||
|
errors::VisibilityNotPermittedNote::TraitImpl,
|
||||||
|
);
|
||||||
|
if let TyKind::Dummy = self_ty.kind {
|
||||||
|
// Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering,
|
||||||
|
// which isn't allowed. Not a problem for this obscure, obsolete syntax.
|
||||||
|
self.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
|
||||||
|
}
|
||||||
|
if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity) {
|
||||||
|
self.dcx().emit_err(errors::UnsafeNegativeImpl {
|
||||||
|
span: sp.to(t.path.span),
|
||||||
|
negative: sp,
|
||||||
|
r#unsafe: span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let disallowed = matches!(constness, Const::No)
|
||||||
|
.then(|| TildeConstReason::TraitImpl { span: item.span });
|
||||||
|
self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
|
||||||
|
self.visit_trait_ref(t);
|
||||||
|
self.visit_ty(self_ty);
|
||||||
|
|
||||||
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
|
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
|
||||||
this.visibility_not_permitted(
|
|
||||||
&item.vis,
|
|
||||||
errors::VisibilityNotPermittedNote::TraitImpl,
|
|
||||||
);
|
|
||||||
if let TyKind::Dummy = self_ty.kind {
|
|
||||||
// Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering,
|
|
||||||
// which isn't allowed. Not a problem for this obscure, obsolete syntax.
|
|
||||||
this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
|
|
||||||
}
|
|
||||||
if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity)
|
|
||||||
{
|
|
||||||
this.dcx().emit_err(errors::UnsafeNegativeImpl {
|
|
||||||
span: sp.to(t.path.span),
|
|
||||||
negative: sp,
|
|
||||||
r#unsafe: span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.visit_vis(&item.vis);
|
|
||||||
let disallowed = matches!(constness, Const::No)
|
|
||||||
.then(|| TildeConstReason::TraitImpl { span: item.span });
|
|
||||||
this.with_tilde_const(disallowed, |this| this.visit_generics(generics));
|
|
||||||
this.visit_trait_ref(t);
|
|
||||||
this.visit_ty(self_ty);
|
|
||||||
|
|
||||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
|
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
|
||||||
});
|
});
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
return; // Avoid visiting again.
|
|
||||||
}
|
}
|
||||||
ItemKind::Impl(box Impl {
|
ItemKind::Impl(box Impl {
|
||||||
safety,
|
safety,
|
||||||
|
@ -883,39 +900,36 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
only_trait,
|
only_trait,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.with_in_trait_impl(None, |this| {
|
self.visit_attrs_vis(&item.attrs, &item.vis);
|
||||||
this.visibility_not_permitted(
|
self.visibility_not_permitted(
|
||||||
&item.vis,
|
&item.vis,
|
||||||
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
||||||
);
|
);
|
||||||
if let &Safety::Unsafe(span) = safety {
|
if let &Safety::Unsafe(span) = safety {
|
||||||
this.dcx().emit_err(errors::InherentImplCannotUnsafe {
|
self.dcx().emit_err(errors::InherentImplCannotUnsafe {
|
||||||
span: self_ty.span,
|
span: self_ty.span,
|
||||||
annotation_span: span,
|
annotation_span: span,
|
||||||
annotation: "unsafe",
|
annotation: "unsafe",
|
||||||
self_ty: self_ty.span,
|
self_ty: self_ty.span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let &ImplPolarity::Negative(span) = polarity {
|
if let &ImplPolarity::Negative(span) = polarity {
|
||||||
this.dcx().emit_err(error(span, "negative", false));
|
self.dcx().emit_err(error(span, "negative", false));
|
||||||
}
|
}
|
||||||
if let &Defaultness::Default(def_span) = defaultness {
|
if let &Defaultness::Default(def_span) = defaultness {
|
||||||
this.dcx().emit_err(error(def_span, "`default`", true));
|
self.dcx().emit_err(error(def_span, "`default`", true));
|
||||||
}
|
}
|
||||||
if let &Const::Yes(span) = constness {
|
if let &Const::Yes(span) = constness {
|
||||||
this.dcx().emit_err(error(span, "`const`", true));
|
self.dcx().emit_err(error(span, "`const`", true));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.visit_vis(&item.vis);
|
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
|
||||||
this.with_tilde_const(
|
this.visit_generics(generics)
|
||||||
Some(TildeConstReason::Impl { span: item.span }),
|
});
|
||||||
|this| this.visit_generics(generics),
|
self.visit_ty(self_ty);
|
||||||
);
|
self.with_in_trait_impl(None, |this| {
|
||||||
this.visit_ty(self_ty);
|
|
||||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
|
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
|
||||||
});
|
});
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
return; // Avoid visiting again.
|
|
||||||
}
|
}
|
||||||
ItemKind::Fn(
|
ItemKind::Fn(
|
||||||
func @ box Fn {
|
func @ box Fn {
|
||||||
|
@ -928,6 +942,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
define_opaque: _,
|
define_opaque: _,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
|
|
||||||
let is_intrinsic =
|
let is_intrinsic =
|
||||||
|
@ -955,43 +970,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_vis(&item.vis);
|
|
||||||
self.visit_ident(ident);
|
|
||||||
let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
|
let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
|
||||||
self.visit_fn(kind, item.span, item.id);
|
self.visit_fn(kind, item.span, item.id);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
return; // Avoid visiting again.
|
|
||||||
}
|
}
|
||||||
ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
|
ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
|
||||||
|
let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));
|
||||||
|
self.visibility_not_permitted(
|
||||||
|
&item.vis,
|
||||||
|
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||||
|
);
|
||||||
|
|
||||||
|
if &Safety::Default == safety {
|
||||||
|
if item.span.at_least_rust_2024() {
|
||||||
|
self.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
|
||||||
|
} else {
|
||||||
|
self.lint_buffer.buffer_lint(
|
||||||
|
MISSING_UNSAFE_ON_EXTERN,
|
||||||
|
item.id,
|
||||||
|
item.span,
|
||||||
|
BuiltinLintDiag::MissingUnsafeOnExtern {
|
||||||
|
suggestion: item.span.shrink_to_lo(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if abi.is_none() {
|
||||||
|
self.maybe_lint_missing_abi(*extern_span, item.id);
|
||||||
|
}
|
||||||
self.with_in_extern_mod(*safety, |this| {
|
self.with_in_extern_mod(*safety, |this| {
|
||||||
let old_item = mem::replace(&mut this.extern_mod, Some(item.span));
|
|
||||||
this.visibility_not_permitted(
|
|
||||||
&item.vis,
|
|
||||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
|
||||||
);
|
|
||||||
|
|
||||||
if &Safety::Default == safety {
|
|
||||||
if item.span.at_least_rust_2024() {
|
|
||||||
this.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
|
|
||||||
} else {
|
|
||||||
this.lint_buffer.buffer_lint(
|
|
||||||
MISSING_UNSAFE_ON_EXTERN,
|
|
||||||
item.id,
|
|
||||||
item.span,
|
|
||||||
BuiltinLintDiag::MissingUnsafeOnExtern {
|
|
||||||
suggestion: item.span.shrink_to_lo(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if abi.is_none() {
|
|
||||||
this.maybe_lint_missing_abi(*extern_span, item.id);
|
|
||||||
}
|
|
||||||
visit::walk_item(this, item);
|
visit::walk_item(this, item);
|
||||||
this.extern_mod = old_item;
|
|
||||||
});
|
});
|
||||||
return; // Avoid visiting again.
|
self.extern_mod_span = old_item;
|
||||||
}
|
}
|
||||||
ItemKind::Enum(_, def, _) => {
|
ItemKind::Enum(_, def, _) => {
|
||||||
for variant in &def.variants {
|
for variant in &def.variants {
|
||||||
|
@ -1006,34 +1016,31 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
visit::walk_item(self, item)
|
||||||
}
|
}
|
||||||
ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => {
|
ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => {
|
||||||
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
let is_const_trait =
|
let is_const_trait =
|
||||||
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
|
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
|
||||||
self.with_in_trait(item.span, is_const_trait, |this| {
|
if *is_auto == IsAuto::Yes {
|
||||||
if *is_auto == IsAuto::Yes {
|
// Auto traits cannot have generics, super traits nor contain items.
|
||||||
// Auto traits cannot have generics, super traits nor contain items.
|
self.deny_generic_params(generics, ident.span);
|
||||||
this.deny_generic_params(generics, ident.span);
|
self.deny_super_traits(bounds, ident.span);
|
||||||
this.deny_super_traits(bounds, ident.span);
|
self.deny_where_clause(&generics.where_clause, ident.span);
|
||||||
this.deny_where_clause(&generics.where_clause, ident.span);
|
self.deny_items(items, ident.span);
|
||||||
this.deny_items(items, ident.span);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
|
||||||
// context for the supertraits.
|
// context for the supertraits.
|
||||||
this.visit_vis(&item.vis);
|
let disallowed =
|
||||||
this.visit_ident(ident);
|
is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span });
|
||||||
let disallowed = is_const_trait
|
self.with_tilde_const(disallowed, |this| {
|
||||||
.is_none()
|
this.visit_generics(generics);
|
||||||
.then(|| TildeConstReason::Trait { span: item.span });
|
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||||
this.with_tilde_const(disallowed, |this| {
|
});
|
||||||
this.visit_generics(generics);
|
self.with_in_trait(item.span, is_const_trait, |this| {
|
||||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
|
||||||
});
|
|
||||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
|
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
|
||||||
});
|
});
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
return; // Avoid visiting again
|
|
||||||
}
|
}
|
||||||
ItemKind::Mod(safety, ident, mod_kind) => {
|
ItemKind::Mod(safety, ident, mod_kind) => {
|
||||||
if let &Safety::Unsafe(span) = safety {
|
if let &Safety::Unsafe(span) = safety {
|
||||||
|
@ -1045,18 +1052,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
{
|
{
|
||||||
self.check_mod_file_item_asciionly(*ident);
|
self.check_mod_file_item_asciionly(*ident);
|
||||||
}
|
}
|
||||||
|
visit::walk_item(self, item)
|
||||||
}
|
}
|
||||||
ItemKind::Struct(ident, vdata, generics) => match vdata {
|
ItemKind::Struct(ident, vdata, generics) => match vdata {
|
||||||
VariantData::Struct { fields, .. } => {
|
VariantData::Struct { fields, .. } => {
|
||||||
self.visit_vis(&item.vis);
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
self.visit_ident(ident);
|
|
||||||
self.visit_generics(generics);
|
self.visit_generics(generics);
|
||||||
// Permit `Anon{Struct,Union}` as field type.
|
// Permit `Anon{Struct,Union}` as field type.
|
||||||
walk_list!(self, visit_struct_field_def, fields);
|
walk_list!(self, visit_struct_field_def, fields);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => visit::walk_item(self, item),
|
||||||
},
|
},
|
||||||
ItemKind::Union(ident, vdata, generics) => {
|
ItemKind::Union(ident, vdata, generics) => {
|
||||||
if vdata.fields().is_empty() {
|
if vdata.fields().is_empty() {
|
||||||
|
@ -1064,15 +1069,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
}
|
}
|
||||||
match vdata {
|
match vdata {
|
||||||
VariantData::Struct { fields, .. } => {
|
VariantData::Struct { fields, .. } => {
|
||||||
self.visit_vis(&item.vis);
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
self.visit_ident(ident);
|
|
||||||
self.visit_generics(generics);
|
self.visit_generics(generics);
|
||||||
// Permit `Anon{Struct,Union}` as field type.
|
// Permit `Anon{Struct,Union}` as field type.
|
||||||
walk_list!(self, visit_struct_field_def, fields);
|
walk_list!(self, visit_struct_field_def, fields);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => visit::walk_item(self, item),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
|
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
|
||||||
|
@ -1083,6 +1085,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
visit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
|
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
|
||||||
self.check_item_safety(item.span, *safety);
|
self.check_item_safety(item.span, *safety);
|
||||||
|
@ -1096,6 +1099,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
replace_span: self.ending_semi_or_hi(item.span),
|
replace_span: self.ending_semi_or_hi(item.span),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
visit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
ItemKind::TyAlias(
|
ItemKind::TyAlias(
|
||||||
ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
|
ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
|
||||||
|
@ -1119,11 +1123,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
help: self.sess.is_nightly_build(),
|
help: self.sess.is_nightly_build(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
visit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => visit::walk_item(self, item),
|
||||||
}
|
}
|
||||||
|
|
||||||
visit::walk_item(self, item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||||
|
@ -1488,10 +1491,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
|| ctxt == AssocCtxt::Trait
|
|| ctxt == AssocCtxt::Trait
|
||||||
|| matches!(func.sig.header.constness, Const::Yes(_)) =>
|
|| matches!(func.sig.header.constness, Const::Yes(_)) =>
|
||||||
{
|
{
|
||||||
self.visit_vis(&item.vis);
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
|
||||||
self.visit_ident(&func.ident);
|
|
||||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
|
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
|
||||||
self.visit_fn(kind, item.span, item.id);
|
self.visit_fn(kind, item.span, item.id);
|
||||||
}
|
}
|
||||||
AssocItemKind::Type(_) => {
|
AssocItemKind::Type(_) => {
|
||||||
|
@ -1596,7 +1597,7 @@ fn deny_equality_constraints(
|
||||||
generics.where_clause.span
|
generics.where_clause.span
|
||||||
} else {
|
} else {
|
||||||
let mut span = predicate_span;
|
let mut span = predicate_span;
|
||||||
let mut prev: Option<Span> = None;
|
let mut prev_span: Option<Span> = None;
|
||||||
let mut preds = generics.where_clause.predicates.iter().peekable();
|
let mut preds = generics.where_clause.predicates.iter().peekable();
|
||||||
// Find the predicate that shouldn't have been in the where bound list.
|
// Find the predicate that shouldn't have been in the where bound list.
|
||||||
while let Some(pred) = preds.next() {
|
while let Some(pred) = preds.next() {
|
||||||
|
@ -1606,12 +1607,12 @@ fn deny_equality_constraints(
|
||||||
if let Some(next) = preds.peek() {
|
if let Some(next) = preds.peek() {
|
||||||
// This is the first predicate, remove the trailing comma as well.
|
// This is the first predicate, remove the trailing comma as well.
|
||||||
span = span.with_hi(next.span.lo());
|
span = span.with_hi(next.span.lo());
|
||||||
} else if let Some(prev) = prev {
|
} else if let Some(prev_span) = prev_span {
|
||||||
// Remove the previous comma as well.
|
// Remove the previous comma as well.
|
||||||
span = span.with_lo(prev.hi());
|
span = span.with_lo(prev_span.hi());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prev = Some(pred.span);
|
prev_span = Some(pred.span);
|
||||||
}
|
}
|
||||||
span
|
span
|
||||||
};
|
};
|
||||||
|
@ -1686,10 +1687,10 @@ pub fn check_crate(
|
||||||
let mut validator = AstValidator {
|
let mut validator = AstValidator {
|
||||||
sess,
|
sess,
|
||||||
features,
|
features,
|
||||||
extern_mod: None,
|
extern_mod_span: None,
|
||||||
outer_trait_or_trait_impl: None,
|
outer_trait_or_trait_impl: None,
|
||||||
has_proc_macro_decls: false,
|
has_proc_macro_decls: false,
|
||||||
outer_impl_trait: None,
|
outer_impl_trait_span: None,
|
||||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||||
extern_mod_safety: None,
|
extern_mod_safety: None,
|
||||||
lint_buffer: lints,
|
lint_buffer: lints,
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
|
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::{fmt, mem, ptr};
|
use std::{fmt, ptr};
|
||||||
|
|
||||||
use rustc_abi::{Align, HasDataLayout, Size};
|
use rustc_abi::{Align, HasDataLayout, Size};
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
|
@ -131,7 +132,7 @@ pub struct Memory<'tcx, M: Machine<'tcx>> {
|
||||||
/// This stores whether we are currently doing reads purely for the purpose of validation.
|
/// This stores whether we are currently doing reads purely for the purpose of validation.
|
||||||
/// Those reads do not trigger the machine's hooks for memory reads.
|
/// Those reads do not trigger the machine's hooks for memory reads.
|
||||||
/// Needless to say, this must only be set with great care!
|
/// Needless to say, this must only be set with great care!
|
||||||
validation_in_progress: bool,
|
validation_in_progress: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reference to some allocation that was already bounds-checked for the given region
|
/// A reference to some allocation that was already bounds-checked for the given region
|
||||||
|
@ -158,7 +159,7 @@ impl<'tcx, M: Machine<'tcx>> Memory<'tcx, M> {
|
||||||
alloc_map: M::MemoryMap::default(),
|
alloc_map: M::MemoryMap::default(),
|
||||||
extra_fn_ptr_map: FxIndexMap::default(),
|
extra_fn_ptr_map: FxIndexMap::default(),
|
||||||
dead_alloc_map: FxIndexMap::default(),
|
dead_alloc_map: FxIndexMap::default(),
|
||||||
validation_in_progress: false,
|
validation_in_progress: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,7 +716,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
// We want to call the hook on *all* accesses that involve an AllocId, including zero-sized
|
// We want to call the hook on *all* accesses that involve an AllocId, including zero-sized
|
||||||
// accesses. That means we cannot rely on the closure above or the `Some` branch below. We
|
// accesses. That means we cannot rely on the closure above or the `Some` branch below. We
|
||||||
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
|
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
|
||||||
if !self.memory.validation_in_progress {
|
if !self.memory.validation_in_progress.get() {
|
||||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
|
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
|
||||||
M::before_alloc_read(self, alloc_id)?;
|
M::before_alloc_read(self, alloc_id)?;
|
||||||
}
|
}
|
||||||
|
@ -723,7 +724,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
|
|
||||||
if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
|
if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
|
||||||
let range = alloc_range(offset, size);
|
let range = alloc_range(offset, size);
|
||||||
if !self.memory.validation_in_progress {
|
if !self.memory.validation_in_progress.get() {
|
||||||
M::before_memory_read(
|
M::before_memory_read(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
&self.machine,
|
&self.machine,
|
||||||
|
@ -801,7 +802,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||||
{
|
{
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let validation_in_progress = self.memory.validation_in_progress;
|
let validation_in_progress = self.memory.validation_in_progress.get();
|
||||||
|
|
||||||
let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
|
let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
|
||||||
let ptr_and_alloc = Self::check_and_deref_ptr(
|
let ptr_and_alloc = Self::check_and_deref_ptr(
|
||||||
|
@ -1087,23 +1088,43 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
///
|
///
|
||||||
/// We do this so Miri's allocation access tracking does not show the validation
|
/// We do this so Miri's allocation access tracking does not show the validation
|
||||||
/// reads as spurious accesses.
|
/// reads as spurious accesses.
|
||||||
pub fn run_for_validation<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
|
pub fn run_for_validation_mut<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
// This deliberately uses `==` on `bool` to follow the pattern
|
// This deliberately uses `==` on `bool` to follow the pattern
|
||||||
// `assert!(val.replace(new) == old)`.
|
// `assert!(val.replace(new) == old)`.
|
||||||
assert!(
|
assert!(
|
||||||
mem::replace(&mut self.memory.validation_in_progress, true) == false,
|
self.memory.validation_in_progress.replace(true) == false,
|
||||||
"`validation_in_progress` was already set"
|
"`validation_in_progress` was already set"
|
||||||
);
|
);
|
||||||
let res = f(self);
|
let res = f(self);
|
||||||
assert!(
|
assert!(
|
||||||
mem::replace(&mut self.memory.validation_in_progress, false) == true,
|
self.memory.validation_in_progress.replace(false) == true,
|
||||||
|
"`validation_in_progress` was unset by someone else"
|
||||||
|
);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the closure in "validation" mode, which means the machine's memory read hooks will be
|
||||||
|
/// suppressed. Needless to say, this must only be set with great care! Cannot be nested.
|
||||||
|
///
|
||||||
|
/// We do this so Miri's allocation access tracking does not show the validation
|
||||||
|
/// reads as spurious accesses.
|
||||||
|
pub fn run_for_validation_ref<R>(&self, f: impl FnOnce(&Self) -> R) -> R {
|
||||||
|
// This deliberately uses `==` on `bool` to follow the pattern
|
||||||
|
// `assert!(val.replace(new) == old)`.
|
||||||
|
assert!(
|
||||||
|
self.memory.validation_in_progress.replace(true) == false,
|
||||||
|
"`validation_in_progress` was already set"
|
||||||
|
);
|
||||||
|
let res = f(self);
|
||||||
|
assert!(
|
||||||
|
self.memory.validation_in_progress.replace(false) == true,
|
||||||
"`validation_in_progress` was unset by someone else"
|
"`validation_in_progress` was unset by someone else"
|
||||||
);
|
);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn validation_in_progress(&self) -> bool {
|
pub(super) fn validation_in_progress(&self) -> bool {
|
||||||
self.memory.validation_in_progress
|
self.memory.validation_in_progress.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1375,7 +1396,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
};
|
};
|
||||||
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
|
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
|
||||||
let src_range = alloc_range(src_offset, size);
|
let src_range = alloc_range(src_offset, size);
|
||||||
assert!(!self.memory.validation_in_progress, "we can't be copying during validation");
|
assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation");
|
||||||
// For the overlapping case, it is crucial that we trigger the read hook
|
// For the overlapping case, it is crucial that we trigger the read hook
|
||||||
// before the write hook -- the aliasing model cares about the order.
|
// before the write hook -- the aliasing model cares about the order.
|
||||||
M::before_memory_read(
|
M::before_memory_read(
|
||||||
|
|
|
@ -1322,7 +1322,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty);
|
trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty);
|
||||||
|
|
||||||
// Run the visitor.
|
// Run the visitor.
|
||||||
self.run_for_validation(|ecx| {
|
self.run_for_validation_mut(|ecx| {
|
||||||
let reset_padding = reset_provenance_and_padding && {
|
let reset_padding = reset_provenance_and_padding && {
|
||||||
// Check if `val` is actually stored in memory. If not, padding is not even
|
// Check if `val` is actually stored in memory. If not, padding is not even
|
||||||
// represented and we need not reset it.
|
// represented and we need not reset it.
|
||||||
|
|
|
@ -632,10 +632,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||||
self.typeck_results
|
|
||||||
.borrow_mut()
|
|
||||||
.treat_byte_string_as_slice
|
|
||||||
.insert(lt.hir_id.local_id);
|
|
||||||
pat_ty =
|
pat_ty =
|
||||||
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
|
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,9 +81,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
||||||
wbcx.typeck_results.used_trait_imports = used_trait_imports;
|
wbcx.typeck_results.used_trait_imports = used_trait_imports;
|
||||||
|
|
||||||
wbcx.typeck_results.treat_byte_string_as_slice =
|
|
||||||
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
|
|
||||||
|
|
||||||
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
|
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
|
||||||
|
|
||||||
self.tcx.arena.alloc(wbcx.typeck_results)
|
self.tcx.arena.alloc(wbcx.typeck_results)
|
||||||
|
|
|
@ -89,6 +89,7 @@ rustc_query_append!(define_dep_nodes![
|
||||||
/// We use this to create a forever-red node.
|
/// We use this to create a forever-red node.
|
||||||
[] fn Red() -> (),
|
[] fn Red() -> (),
|
||||||
[] fn SideEffect() -> (),
|
[] fn SideEffect() -> (),
|
||||||
|
[] fn AnonZeroDeps() -> (),
|
||||||
[] fn TraitSelect() -> (),
|
[] fn TraitSelect() -> (),
|
||||||
[] fn CompileCodegenUnit() -> (),
|
[] fn CompileCodegenUnit() -> (),
|
||||||
[] fn CompileMonoItem() -> (),
|
[] fn CompileMonoItem() -> (),
|
||||||
|
|
|
@ -53,6 +53,7 @@ impl Deps for DepsType {
|
||||||
const DEP_KIND_NULL: DepKind = dep_kinds::Null;
|
const DEP_KIND_NULL: DepKind = dep_kinds::Null;
|
||||||
const DEP_KIND_RED: DepKind = dep_kinds::Red;
|
const DEP_KIND_RED: DepKind = dep_kinds::Red;
|
||||||
const DEP_KIND_SIDE_EFFECT: DepKind = dep_kinds::SideEffect;
|
const DEP_KIND_SIDE_EFFECT: DepKind = dep_kinds::SideEffect;
|
||||||
|
const DEP_KIND_ANON_ZERO_DEPS: DepKind = dep_kinds::AnonZeroDeps;
|
||||||
const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1;
|
const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,12 +197,6 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
||||||
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
||||||
|
|
||||||
/// We sometimes treat byte string literals (which are of type `&[u8; N]`)
|
|
||||||
/// as `&[u8]`, depending on the pattern in which they are used.
|
|
||||||
/// This hashset records all instances where we behave
|
|
||||||
/// like this to allow `const_to_pat` to reliably handle this situation.
|
|
||||||
pub treat_byte_string_as_slice: ItemLocalSet,
|
|
||||||
|
|
||||||
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
|
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
|
||||||
/// on closure size.
|
/// on closure size.
|
||||||
pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
|
pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
|
||||||
|
@ -237,7 +231,6 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
closure_fake_reads: Default::default(),
|
closure_fake_reads: Default::default(),
|
||||||
rvalue_scopes: Default::default(),
|
rvalue_scopes: Default::default(),
|
||||||
coroutine_stalled_predicates: Default::default(),
|
coroutine_stalled_predicates: Default::default(),
|
||||||
treat_byte_string_as_slice: Default::default(),
|
|
||||||
closure_size_eval: Default::default(),
|
closure_size_eval: Default::default(),
|
||||||
offset_of_data: Default::default(),
|
offset_of_data: Default::default(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,25 +58,13 @@ struct ConstToPat<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
id: hir::HirId,
|
id: hir::HirId,
|
||||||
|
|
||||||
treat_byte_string_as_slice: bool,
|
|
||||||
|
|
||||||
c: ty::Const<'tcx>,
|
c: ty::Const<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ConstToPat<'tcx> {
|
impl<'tcx> ConstToPat<'tcx> {
|
||||||
fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
|
fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
|
||||||
trace!(?pat_ctxt.typeck_results.hir_owner);
|
trace!(?pat_ctxt.typeck_results.hir_owner);
|
||||||
ConstToPat {
|
ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c }
|
||||||
tcx: pat_ctxt.tcx,
|
|
||||||
typing_env: pat_ctxt.typing_env,
|
|
||||||
span,
|
|
||||||
id,
|
|
||||||
treat_byte_string_as_slice: pat_ctxt
|
|
||||||
.typeck_results
|
|
||||||
.treat_byte_string_as_slice
|
|
||||||
.contains(&id.local_id),
|
|
||||||
c,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
|
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
@ -108,8 +96,6 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||||
uv: ty::UnevaluatedConst<'tcx>,
|
uv: ty::UnevaluatedConst<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Box<Pat<'tcx>> {
|
) -> Box<Pat<'tcx>> {
|
||||||
trace!(self.treat_byte_string_as_slice);
|
|
||||||
|
|
||||||
// It's not *technically* correct to be revealing opaque types here as borrowcheck has
|
// It's not *technically* correct to be revealing opaque types here as borrowcheck has
|
||||||
// not run yet. However, CTFE itself uses `TypingMode::PostAnalysis` unconditionally even
|
// not run yet. However, CTFE itself uses `TypingMode::PostAnalysis` unconditionally even
|
||||||
// during typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
|
// during typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
|
||||||
|
@ -307,21 +293,8 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||||
ty,
|
ty,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
|
|
||||||
// matching against references, you can only use byte string literals.
|
|
||||||
// The typechecker has a special case for byte string literals, by treating them
|
|
||||||
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
|
|
||||||
// has no negative effects on pattern matching, even if we're actually matching on
|
|
||||||
// arrays.
|
|
||||||
let pointee_ty = match *pointee_ty.kind() {
|
|
||||||
ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => {
|
|
||||||
Ty::new_slice(tcx, elem_ty)
|
|
||||||
}
|
|
||||||
_ => *pointee_ty,
|
|
||||||
};
|
|
||||||
// References have the same valtree representation as their pointee.
|
// References have the same valtree representation as their pointee.
|
||||||
let subpattern = self.valtree_to_pat(cv, pointee_ty);
|
PatKind::Deref { subpattern: self.valtree_to_pat(cv, *pointee_ty) }
|
||||||
PatKind::Deref { subpattern }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer};
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||||
use rustc_hir::{self as hir, RangeEnd};
|
use rustc_hir::{self as hir, LangItem, RangeEnd};
|
||||||
use rustc_index::Idx;
|
use rustc_index::Idx;
|
||||||
use rustc_middle::mir::interpret::LitToConstInput;
|
use rustc_middle::mir::interpret::LitToConstInput;
|
||||||
use rustc_middle::thir::{
|
use rustc_middle::thir::{
|
||||||
|
@ -130,7 +130,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// Lower the endpoint into a temporary `PatKind` that will then be
|
// Lower the endpoint into a temporary `PatKind` that will then be
|
||||||
// deconstructed to obtain the constant value and other data.
|
// deconstructed to obtain the constant value and other data.
|
||||||
let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr);
|
let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr, None);
|
||||||
|
|
||||||
// Unpeel any ascription or inline-const wrapper nodes.
|
// Unpeel any ascription or inline-const wrapper nodes.
|
||||||
loop {
|
loop {
|
||||||
|
@ -294,7 +294,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
hir::PatKind::Never => PatKind::Never,
|
hir::PatKind::Never => PatKind::Never,
|
||||||
|
|
||||||
hir::PatKind::Expr(value) => self.lower_pat_expr(value),
|
hir::PatKind::Expr(value) => self.lower_pat_expr(value, Some(ty)),
|
||||||
|
|
||||||
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
||||||
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
|
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
|
||||||
|
@ -630,7 +630,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
/// - Paths (e.g. `FOO`, `foo::BAR`, `Option::None`)
|
/// - Paths (e.g. `FOO`, `foo::BAR`, `Option::None`)
|
||||||
/// - Inline const blocks (e.g. `const { 1 + 1 }`)
|
/// - Inline const blocks (e.g. `const { 1 + 1 }`)
|
||||||
/// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
|
/// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
|
||||||
fn lower_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
|
fn lower_pat_expr(
|
||||||
|
&mut self,
|
||||||
|
expr: &'tcx hir::PatExpr<'tcx>,
|
||||||
|
pat_ty: Option<Ty<'tcx>>,
|
||||||
|
) -> PatKind<'tcx> {
|
||||||
let (lit, neg) = match &expr.kind {
|
let (lit, neg) = match &expr.kind {
|
||||||
hir::PatExprKind::Path(qpath) => {
|
hir::PatExprKind::Path(qpath) => {
|
||||||
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
|
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
|
||||||
|
@ -641,7 +645,31 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
|
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ct_ty = self.typeck_results.node_type(expr.hir_id);
|
// We handle byte string literal patterns by using the pattern's type instead of the
|
||||||
|
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
|
||||||
|
// the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
|
||||||
|
// pattern's type means we'll properly translate it to a slice reference pattern. This works
|
||||||
|
// because slices and arrays have the same valtree representation.
|
||||||
|
// HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if
|
||||||
|
// `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR.
|
||||||
|
// FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is
|
||||||
|
// superseded by a more general implementation of deref patterns.
|
||||||
|
let ct_ty = match pat_ty {
|
||||||
|
Some(pat_ty)
|
||||||
|
if let ty::Adt(def, _) = *pat_ty.kind()
|
||||||
|
&& self.tcx.is_lang_item(def.did(), LangItem::String) =>
|
||||||
|
{
|
||||||
|
if !self.tcx.features().string_deref_patterns() {
|
||||||
|
span_bug!(
|
||||||
|
expr.span,
|
||||||
|
"matching on `String` went through without enabling string_deref_patterns"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.typeck_results.node_type(expr.hir_id)
|
||||||
|
}
|
||||||
|
Some(pat_ty) => pat_ty,
|
||||||
|
None => self.typeck_results.node_type(expr.hir_id),
|
||||||
|
};
|
||||||
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
|
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
|
||||||
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
|
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
|
||||||
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
|
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
|
||||||
|
|
|
@ -2960,13 +2960,30 @@ impl<'a> Parser<'a> {
|
||||||
let parser_snapshot_before_ty = this.create_snapshot_for_diagnostic();
|
let parser_snapshot_before_ty = this.create_snapshot_for_diagnostic();
|
||||||
this.eat_incorrect_doc_comment_for_param_type();
|
this.eat_incorrect_doc_comment_for_param_type();
|
||||||
let mut ty = this.parse_ty_for_param();
|
let mut ty = this.parse_ty_for_param();
|
||||||
if ty.is_ok()
|
|
||||||
&& this.token != token::Comma
|
if let Ok(t) = &ty {
|
||||||
&& this.token != token::CloseDelim(Delimiter::Parenthesis)
|
// Check for trailing angle brackets
|
||||||
{
|
if let TyKind::Path(_, Path { segments, .. }) = &t.kind {
|
||||||
// This wasn't actually a type, but a pattern looking like a type,
|
if let Some(segment) = segments.last() {
|
||||||
// so we are going to rollback and re-parse for recovery.
|
if let Some(guar) =
|
||||||
ty = this.unexpected_any();
|
this.check_trailing_angle_brackets(segment, &[exp!(CloseParen)])
|
||||||
|
{
|
||||||
|
return Ok((
|
||||||
|
dummy_arg(segment.ident, guar),
|
||||||
|
Trailing::No,
|
||||||
|
UsePreAttrPos::No,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.token != token::Comma
|
||||||
|
&& this.token != token::CloseDelim(Delimiter::Parenthesis)
|
||||||
|
{
|
||||||
|
// This wasn't actually a type, but a pattern looking like a type,
|
||||||
|
// so we are going to rollback and re-parse for recovery.
|
||||||
|
ty = this.unexpected_any();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match ty {
|
match ty {
|
||||||
Ok(ty) => {
|
Ok(ty) => {
|
||||||
|
@ -2977,6 +2994,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
// If this is a C-variadic argument and we hit an error, return the error.
|
// If this is a C-variadic argument and we hit an error, return the error.
|
||||||
Err(err) if this.token == token::DotDotDot => return Err(err),
|
Err(err) if this.token == token::DotDotDot => return Err(err),
|
||||||
|
Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err),
|
||||||
// Recover from attempting to parse the argument as a type without pattern.
|
// Recover from attempting to parse the argument as a type without pattern.
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
|
|
|
@ -870,6 +870,17 @@ macro_rules! define_queries {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn AnonZeroDeps<'tcx>() -> DepKindStruct<'tcx> {
|
||||||
|
DepKindStruct {
|
||||||
|
is_anon: true,
|
||||||
|
is_eval_always: false,
|
||||||
|
fingerprint_style: FingerprintStyle::Opaque,
|
||||||
|
force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")),
|
||||||
|
try_load_from_on_disk_cache: None,
|
||||||
|
name: &"AnonZeroDeps",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> {
|
pub(crate) fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> {
|
||||||
DepKindStruct {
|
DepKindStruct {
|
||||||
is_anon: true,
|
is_anon: true,
|
||||||
|
|
|
@ -50,7 +50,7 @@ rustc_index::newtype_index! {
|
||||||
rustc_data_structures::static_assert_size!(Option<DepNodeIndex>, 4);
|
rustc_data_structures::static_assert_size!(Option<DepNodeIndex>, 4);
|
||||||
|
|
||||||
impl DepNodeIndex {
|
impl DepNodeIndex {
|
||||||
const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO;
|
const SINGLETON_ZERO_DEPS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO;
|
||||||
pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
|
pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,13 +140,13 @@ impl<D: Deps> DepGraph<D> {
|
||||||
|
|
||||||
let colors = DepNodeColorMap::new(prev_graph_node_count);
|
let colors = DepNodeColorMap::new(prev_graph_node_count);
|
||||||
|
|
||||||
// Instantiate a dependy-less node only once for anonymous queries.
|
// Instantiate a node with zero dependencies only once for anonymous queries.
|
||||||
let _green_node_index = current.alloc_node(
|
let _green_node_index = current.alloc_node(
|
||||||
DepNode { kind: D::DEP_KIND_NULL, hash: current.anon_id_seed.into() },
|
DepNode { kind: D::DEP_KIND_ANON_ZERO_DEPS, hash: current.anon_id_seed.into() },
|
||||||
EdgesVec::new(),
|
EdgesVec::new(),
|
||||||
Fingerprint::ZERO,
|
Fingerprint::ZERO,
|
||||||
);
|
);
|
||||||
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
|
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE);
|
||||||
|
|
||||||
// Instantiate a dependy-less red node only once for anonymous queries.
|
// Instantiate a dependy-less red node only once for anonymous queries.
|
||||||
let red_node_index = current.alloc_node(
|
let red_node_index = current.alloc_node(
|
||||||
|
@ -407,7 +407,7 @@ impl<D: Deps> DepGraphData<D> {
|
||||||
// going to be (i.e. equal to the precomputed
|
// going to be (i.e. equal to the precomputed
|
||||||
// `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
|
// `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
|
||||||
// a `StableHasher` and sending the node through interning.
|
// a `StableHasher` and sending the node through interning.
|
||||||
DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
|
DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
// When there is only one dependency, don't bother creating a node.
|
// When there is only one dependency, don't bother creating a node.
|
||||||
|
|
|
@ -111,6 +111,9 @@ pub trait Deps {
|
||||||
/// We use this to create a side effect node.
|
/// We use this to create a side effect node.
|
||||||
const DEP_KIND_SIDE_EFFECT: DepKind;
|
const DEP_KIND_SIDE_EFFECT: DepKind;
|
||||||
|
|
||||||
|
/// We use this to create the anon node with zero dependencies.
|
||||||
|
const DEP_KIND_ANON_ZERO_DEPS: DepKind;
|
||||||
|
|
||||||
/// This is the highest value a `DepKind` can have. It's used during encoding to
|
/// This is the highest value a `DepKind` can have. It's used during encoding to
|
||||||
/// pack information into the unused bits.
|
/// pack information into the unused bits.
|
||||||
const DEP_KIND_MAX: u16;
|
const DEP_KIND_MAX: u16;
|
||||||
|
|
|
@ -717,7 +717,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> {
|
||||||
// The program didn't actually do a read, so suppress the memory access hooks.
|
// The program didn't actually do a read, so suppress the memory access hooks.
|
||||||
// This is also a very special exception where we just ignore an error -- if this read
|
// This is also a very special exception where we just ignore an error -- if this read
|
||||||
// was UB e.g. because the memory is uninitialized, we don't want to know!
|
// was UB e.g. because the memory is uninitialized, we don't want to know!
|
||||||
let old_val = this.run_for_validation(|this| this.read_scalar(dest)).discard_err();
|
let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err();
|
||||||
this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
|
this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?;
|
||||||
this.validate_atomic_store(dest, atomic)?;
|
this.validate_atomic_store(dest, atomic)?;
|
||||||
this.buffered_atomic_write(val, dest, atomic, old_val)
|
this.buffered_atomic_write(val, dest, atomic, old_val)
|
||||||
|
|
53
tests/ui/consts/const_in_pattern/arrays-and-slices.rs
Normal file
53
tests/ui/consts/const_in_pattern/arrays-and-slices.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//! Tests that arrays and slices in constants aren't interchangeable when used as patterns.
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
struct SomeStruct<T: ?Sized>(T);
|
||||||
|
|
||||||
|
const BSTR_SIZED: &'static [u8; 3] = b"012";
|
||||||
|
const BSTR_UNSIZED: &'static [u8] = BSTR_SIZED;
|
||||||
|
const STRUCT_SIZED: &'static SomeStruct<[u8; 3]> = &SomeStruct(*BSTR_SIZED);
|
||||||
|
const STRUCT_UNSIZED: &'static SomeStruct<[u8]> = STRUCT_SIZED;
|
||||||
|
|
||||||
|
fn type_mismatches() {
|
||||||
|
// Test that array consts can't be used where a slice pattern is expected. This helps ensure
|
||||||
|
// that `const_to_pat` won't produce irrefutable `thir::PatKind::Array` patterns when matching
|
||||||
|
// on slices, which would result in missing length checks.
|
||||||
|
// See also `tests/ui/match/pattern-deref-miscompile.rs`, which tests that byte string literal
|
||||||
|
// patterns check slices' length appropriately when matching on slices.
|
||||||
|
match BSTR_UNSIZED {
|
||||||
|
BSTR_SIZED => {}
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match STRUCT_UNSIZED {
|
||||||
|
STRUCT_SIZED => {}
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that slice consts can't be used where an array pattern is expected.
|
||||||
|
match BSTR_UNSIZED {
|
||||||
|
BSTR_SIZED => {}
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
// If the types matched here, this would still error, since unsized structs aren't permitted in
|
||||||
|
// constant patterns. See the `invalid_patterns` test below.
|
||||||
|
match STRUCT_UNSIZED {
|
||||||
|
STRUCT_SIZED => {}
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invalid_patterns() {
|
||||||
|
// Test that unsized structs containing slices can't be used as patterns.
|
||||||
|
// See `tests/ui/consts/issue-87046.rs` for an example with `str`.
|
||||||
|
match STRUCT_UNSIZED {
|
||||||
|
STRUCT_UNSIZED => {}
|
||||||
|
//~^ ERROR: cannot use unsized non-slice type `SomeStruct<[u8]>` in constant patterns
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
84
tests/ui/consts/const_in_pattern/arrays-and-slices.stderr
Normal file
84
tests/ui/consts/const_in_pattern/arrays-and-slices.stderr
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/arrays-and-slices.rs:18:9
|
||||||
|
|
|
||||||
|
LL | const BSTR_SIZED: &'static [u8; 3] = b"012";
|
||||||
|
| ---------------------------------- constant defined here
|
||||||
|
...
|
||||||
|
LL | match BSTR_UNSIZED {
|
||||||
|
| ------------ this expression has type `&[u8]`
|
||||||
|
LL | BSTR_SIZED => {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `&[u8]`, found `&[u8; 3]`
|
||||||
|
| `BSTR_SIZED` is interpreted as a constant, not a new binding
|
||||||
|
| help: introduce a new binding instead: `other_bstr_sized`
|
||||||
|
|
|
||||||
|
= note: expected reference `&[u8]`
|
||||||
|
found reference `&'static [u8; 3]`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/arrays-and-slices.rs:23:9
|
||||||
|
|
|
||||||
|
LL | const STRUCT_SIZED: &'static SomeStruct<[u8; 3]> = &SomeStruct(*BSTR_SIZED);
|
||||||
|
| ------------------------------------------------ constant defined here
|
||||||
|
...
|
||||||
|
LL | match STRUCT_UNSIZED {
|
||||||
|
| -------------- this expression has type `&SomeStruct<[u8]>`
|
||||||
|
LL | STRUCT_SIZED => {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>`
|
||||||
|
| `STRUCT_SIZED` is interpreted as a constant, not a new binding
|
||||||
|
| help: introduce a new binding instead: `other_struct_sized`
|
||||||
|
|
|
||||||
|
= note: expected reference `&SomeStruct<[u8]>`
|
||||||
|
found reference `&'static SomeStruct<[u8; 3]>`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/arrays-and-slices.rs:30:9
|
||||||
|
|
|
||||||
|
LL | const BSTR_SIZED: &'static [u8; 3] = b"012";
|
||||||
|
| ---------------------------------- constant defined here
|
||||||
|
...
|
||||||
|
LL | match BSTR_UNSIZED {
|
||||||
|
| ------------ this expression has type `&[u8]`
|
||||||
|
LL | BSTR_SIZED => {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `&[u8]`, found `&[u8; 3]`
|
||||||
|
| `BSTR_SIZED` is interpreted as a constant, not a new binding
|
||||||
|
| help: introduce a new binding instead: `other_bstr_sized`
|
||||||
|
|
|
||||||
|
= note: expected reference `&[u8]`
|
||||||
|
found reference `&'static [u8; 3]`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/arrays-and-slices.rs:37:9
|
||||||
|
|
|
||||||
|
LL | const STRUCT_SIZED: &'static SomeStruct<[u8; 3]> = &SomeStruct(*BSTR_SIZED);
|
||||||
|
| ------------------------------------------------ constant defined here
|
||||||
|
...
|
||||||
|
LL | match STRUCT_UNSIZED {
|
||||||
|
| -------------- this expression has type `&SomeStruct<[u8]>`
|
||||||
|
LL | STRUCT_SIZED => {}
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>`
|
||||||
|
| `STRUCT_SIZED` is interpreted as a constant, not a new binding
|
||||||
|
| help: introduce a new binding instead: `other_struct_sized`
|
||||||
|
|
|
||||||
|
= note: expected reference `&SomeStruct<[u8]>`
|
||||||
|
found reference `&'static SomeStruct<[u8; 3]>`
|
||||||
|
|
||||||
|
error: cannot use unsized non-slice type `SomeStruct<[u8]>` in constant patterns
|
||||||
|
--> $DIR/arrays-and-slices.rs:47:9
|
||||||
|
|
|
||||||
|
LL | const STRUCT_UNSIZED: &'static SomeStruct<[u8]> = STRUCT_SIZED;
|
||||||
|
| ----------------------------------------------- constant defined here
|
||||||
|
...
|
||||||
|
LL | STRUCT_UNSIZED => {}
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -43,6 +43,21 @@ LL - #[coverage = "off"]
|
||||||
LL + #[coverage(on)]
|
LL + #[coverage(on)]
|
||||||
|
|
|
|
||||||
|
|
||||||
|
error: malformed `coverage` attribute input
|
||||||
|
--> $DIR/name-value.rs:26:1
|
||||||
|
|
|
||||||
|
LL | #[coverage = "off"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: the following are the possible correct uses
|
||||||
|
|
|
||||||
|
LL - #[coverage = "off"]
|
||||||
|
LL + #[coverage(off)]
|
||||||
|
|
|
||||||
|
LL - #[coverage = "off"]
|
||||||
|
LL + #[coverage(on)]
|
||||||
|
|
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/name-value.rs:29:5
|
--> $DIR/name-value.rs:29:5
|
||||||
|
|
|
|
||||||
|
@ -59,7 +74,7 @@ LL + #[coverage(on)]
|
||||||
|
|
|
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/name-value.rs:26:1
|
--> $DIR/name-value.rs:35:1
|
||||||
|
|
|
|
||||||
LL | #[coverage = "off"]
|
LL | #[coverage = "off"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -104,7 +119,7 @@ LL + #[coverage(on)]
|
||||||
|
|
|
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/name-value.rs:35:1
|
--> $DIR/name-value.rs:50:1
|
||||||
|
|
|
|
||||||
LL | #[coverage = "off"]
|
LL | #[coverage = "off"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -148,21 +163,6 @@ LL - #[coverage = "off"]
|
||||||
LL + #[coverage(on)]
|
LL + #[coverage(on)]
|
||||||
|
|
|
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
|
||||||
--> $DIR/name-value.rs:50:1
|
|
||||||
|
|
|
||||||
LL | #[coverage = "off"]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
help: the following are the possible correct uses
|
|
||||||
|
|
|
||||||
LL - #[coverage = "off"]
|
|
||||||
LL + #[coverage(off)]
|
|
||||||
|
|
|
||||||
LL - #[coverage = "off"]
|
|
||||||
LL + #[coverage(on)]
|
|
||||||
|
|
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/name-value.rs:64:1
|
--> $DIR/name-value.rs:64:1
|
||||||
|
|
|
|
||||||
|
|
|
@ -37,6 +37,19 @@ LL | #[coverage(off)]
|
||||||
LL | #[coverage(on)]
|
LL | #[coverage(on)]
|
||||||
| ++++
|
| ++++
|
||||||
|
|
||||||
|
error: malformed `coverage` attribute input
|
||||||
|
--> $DIR/word-only.rs:26:1
|
||||||
|
|
|
||||||
|
LL | #[coverage]
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: the following are the possible correct uses
|
||||||
|
|
|
||||||
|
LL | #[coverage(off)]
|
||||||
|
| +++++
|
||||||
|
LL | #[coverage(on)]
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/word-only.rs:29:5
|
--> $DIR/word-only.rs:29:5
|
||||||
|
|
|
|
||||||
|
@ -51,7 +64,7 @@ LL | #[coverage(on)]
|
||||||
| ++++
|
| ++++
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/word-only.rs:26:1
|
--> $DIR/word-only.rs:35:1
|
||||||
|
|
|
|
||||||
LL | #[coverage]
|
LL | #[coverage]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -90,7 +103,7 @@ LL | #[coverage(on)]
|
||||||
| ++++
|
| ++++
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/word-only.rs:35:1
|
--> $DIR/word-only.rs:50:1
|
||||||
|
|
|
|
||||||
LL | #[coverage]
|
LL | #[coverage]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -128,19 +141,6 @@ LL | #[coverage(off)]
|
||||||
LL | #[coverage(on)]
|
LL | #[coverage(on)]
|
||||||
| ++++
|
| ++++
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
|
||||||
--> $DIR/word-only.rs:50:1
|
|
||||||
|
|
|
||||||
LL | #[coverage]
|
|
||||||
| ^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
help: the following are the possible correct uses
|
|
||||||
|
|
|
||||||
LL | #[coverage(off)]
|
|
||||||
| +++++
|
|
||||||
LL | #[coverage(on)]
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error: malformed `coverage` attribute input
|
error: malformed `coverage` attribute input
|
||||||
--> $DIR/word-only.rs:64:1
|
--> $DIR/word-only.rs:64:1
|
||||||
|
|
|
|
||||||
|
|
8
tests/ui/fn/bad-turbofish-hints-issue-121901.rs
Normal file
8
tests/ui/fn/bad-turbofish-hints-issue-121901.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Regression test for the parser wrongfully suggesting turbofish syntax in below syntax errors
|
||||||
|
|
||||||
|
type One = for<'a> fn(Box<dyn Send + 'a);
|
||||||
|
//~^ ERROR: expected one of `+`, `,`, or `>`, found `)`
|
||||||
|
type Two = for<'a> fn(Box<dyn Send + 'a>>);
|
||||||
|
//~^ ERROR: unmatched angle bracket
|
||||||
|
|
||||||
|
fn main() {}
|
25
tests/ui/fn/bad-turbofish-hints-issue-121901.stderr
Normal file
25
tests/ui/fn/bad-turbofish-hints-issue-121901.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error: expected one of `+`, `,`, or `>`, found `)`
|
||||||
|
--> $DIR/bad-turbofish-hints-issue-121901.rs:3:40
|
||||||
|
|
|
||||||
|
LL | type One = for<'a> fn(Box<dyn Send + 'a);
|
||||||
|
| ^ expected one of `+`, `,`, or `>`
|
||||||
|
|
|
||||||
|
help: you might have meant to end the type parameters here
|
||||||
|
|
|
||||||
|
LL | type One = for<'a> fn(Box<dyn Send + 'a>);
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: unmatched angle bracket
|
||||||
|
--> $DIR/bad-turbofish-hints-issue-121901.rs:5:41
|
||||||
|
|
|
||||||
|
LL | type Two = for<'a> fn(Box<dyn Send + 'a>>);
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: remove extra angle bracket
|
||||||
|
|
|
||||||
|
LL - type Two = for<'a> fn(Box<dyn Send + 'a>>);
|
||||||
|
LL + type Two = for<'a> fn(Box<dyn Send + 'a>);
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -1190,8 +1190,8 @@ docs = [
|
||||||
"@ehuss",
|
"@ehuss",
|
||||||
"@GuillaumeGomez",
|
"@GuillaumeGomez",
|
||||||
]
|
]
|
||||||
|
|
||||||
codegen = [
|
codegen = [
|
||||||
|
"@dianqk",
|
||||||
"@saethlin",
|
"@saethlin",
|
||||||
"@workingjubilee",
|
"@workingjubilee",
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue