Auto merge of #131948 - matthiaskrgr:rollup-c9rvzu6, r=matthiaskrgr

Rollup of 12 pull requests

Successful merges:

 - #116863 (warn less about non-exhaustive in ffi)
 - #127675 (Remove invalid help diagnostics for const pointer)
 - #131772 (Remove `const_refs_to_static` TODO in proc_macro)
 - #131789 (Make sure that outer opaques capture inner opaques's lifetimes even with precise capturing syntax)
 - #131795 (Stop inverting expectation in normalization errors)
 - #131920 (Add codegen test for branchy bool match)
 - #131921 (replace STATX_ALL with (STATX_BASIC_STATS | STATX_BTIME) as former is deprecated)
 - #131925 (Warn on redundant `--cfg` directive when revisions are used)
 - #131931 (Remove unnecessary constness from `lower_generic_args_of_path`)
 - #131932 (use tracked_path in rustc_fluent_macro)
 - #131936 (feat(rustdoc-json-types): introduce rustc-hash feature)
 - #131939 (Get rid of `OnlySelfBounds`)

Failed merges:

 - #131181 (Compiletest: Custom differ)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-10-19 22:33:42 +00:00
commit b596184f3b
51 changed files with 437 additions and 374 deletions

View File

@ -1574,7 +1574,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.collect();
// Introduce extra lifetimes if late resolution tells us to.
let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
let extra_lifetimes = self.resolver.extra_lifetime_params(parent_node_id);
params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(
ident,

View File

@ -268,8 +268,8 @@ impl ResolverAstLowering {
///
/// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
/// should appear at the enclosing `PolyTraitRef`.
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
}
}
@ -885,7 +885,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let mut generic_params: Vec<_> = self
.lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder)
.collect();
let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
let extra_lifetimes = self.resolver.extra_lifetime_params(binder);
debug!(?extra_lifetimes);
generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder)
@ -1495,62 +1495,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
let captured_lifetimes_to_duplicate = if let Some(args) =
// We only look for one `use<...>` syntax since we syntactially reject more than one.
bounds.iter().find_map(
|bound| match bound {
ast::GenericBound::Use(a, _) => Some(a),
_ => None,
},
) {
// We'll actually validate these later on; all we need is the list of
// lifetimes to duplicate during this portion of lowering.
args.iter()
.filter_map(|arg| match arg {
PreciseCapturingArg::Lifetime(lt) => Some(*lt),
PreciseCapturingArg::Arg(..) => None,
})
// Add in all the lifetimes mentioned in the bounds. We will error
// them out later, but capturing them here is important to make sure
// they actually get resolved in resolve_bound_vars.
.chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds))
.collect()
} else {
match origin {
hir::OpaqueTyOrigin::TyAlias { .. } => {
// type alias impl trait and associated type position impl trait were
// decided to capture all in-scope lifetimes, which we collect for
// all opaques during resolution.
self.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect()
}
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => {
if in_trait_or_impl.is_some()
|| self.tcx.features().lifetime_capture_rules_2024
|| span.at_least_rust_2024()
{
// return-position impl trait in trait was decided to capture all
// in-scope lifetimes, which we collect for all opaques during resolution.
self.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect()
} else {
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
// example, we only need to duplicate lifetimes that appear in the
// bounds, since those are the only ones that are captured by the opaque.
lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)
}
}
hir::OpaqueTyOrigin::AsyncFn { .. } => {
unreachable!("should be using `lower_async_fn_ret_ty`")
}
// Whether this opaque always captures lifetimes in scope.
// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024`
// is enabled. We don't check the span of the edition, since this is done
// on a per-opaque basis to account for nested opaques.
let always_capture_in_scope = match origin {
_ if self.tcx.features().lifetime_capture_rules_2024 => true,
hir::OpaqueTyOrigin::TyAlias { .. } => true,
hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
hir::OpaqueTyOrigin::AsyncFn { .. } => {
unreachable!("should be using `lower_coroutine_fn_ret_ty`")
}
};
let captured_lifetimes_to_duplicate = lifetime_collector::lifetimes_for_opaque(
self.resolver,
always_capture_in_scope,
opaque_ty_node_id,
bounds,
span,
);
debug!(?captured_lifetimes_to_duplicate);
// Feature gate for RPITIT + use<..>
@ -1920,7 +1883,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let captured_lifetimes = self
.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect();

View File

@ -1,5 +1,7 @@
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
use rustc_ast::{
GenericBound, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def::{DefKind, LifetimeRes, Res};
use rustc_middle::span_bug;
@ -10,14 +12,41 @@ use rustc_span::symbol::{Ident, kw};
use super::ResolverAstLoweringExt;
struct LifetimeCollectVisitor<'ast> {
resolver: &'ast ResolverAstLowering,
resolver: &'ast mut ResolverAstLowering,
always_capture_in_scope: bool,
current_binders: Vec<NodeId>,
collected_lifetimes: FxIndexSet<Lifetime>,
}
impl<'ast> LifetimeCollectVisitor<'ast> {
fn new(resolver: &'ast ResolverAstLowering) -> Self {
Self { resolver, current_binders: Vec::new(), collected_lifetimes: FxIndexSet::default() }
fn new(resolver: &'ast mut ResolverAstLowering, always_capture_in_scope: bool) -> Self {
Self {
resolver,
always_capture_in_scope,
current_binders: Vec::new(),
collected_lifetimes: FxIndexSet::default(),
}
}
fn visit_opaque(&mut self, opaque_ty_node_id: NodeId, bounds: &'ast GenericBounds, span: Span) {
// If we're edition 2024 or within a TAIT or RPITIT, *and* there is no
// `use<>` statement to override the default capture behavior, then
// capture all of the in-scope lifetimes.
if (self.always_capture_in_scope || span.at_least_rust_2024())
&& bounds.iter().all(|bound| !matches!(bound, GenericBound::Use(..)))
{
for (ident, id, _) in self.resolver.extra_lifetime_params(opaque_ty_node_id) {
self.record_lifetime_use(Lifetime { id, ident });
}
}
// We also recurse on the bounds to make sure we capture all the lifetimes
// mentioned in the bounds. These may disagree with the `use<>` list, in which
// case we will error on these later. We will also recurse to visit any
// nested opaques, which may *implicitly* capture lifetimes.
for bound in bounds {
self.visit_param_bound(bound, BoundKind::Bound);
}
}
fn record_lifetime_use(&mut self, lifetime: Lifetime) {
@ -99,6 +128,9 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
self.record_elided_anchor(t.id, t.span);
visit::walk_ty(self, t);
}
TyKind::ImplTrait(opaque_ty_node_id, bounds) => {
self.visit_opaque(*opaque_ty_node_id, bounds, t.span)
}
_ => {
visit::walk_ty(self, t);
}
@ -106,13 +138,14 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
}
}
pub(crate) fn lifetimes_in_bounds(
resolver: &ResolverAstLowering,
pub(crate) fn lifetimes_for_opaque(
resolver: &mut ResolverAstLowering,
always_capture_in_scope: bool,
opaque_ty_node_id: NodeId,
bounds: &GenericBounds,
span: Span,
) -> FxIndexSet<Lifetime> {
let mut visitor = LifetimeCollectVisitor::new(resolver);
for bound in bounds {
visitor.visit_param_bound(bound, BoundKind::Bound);
}
let mut visitor = LifetimeCollectVisitor::new(resolver, always_capture_in_scope);
visitor.visit_opaque(opaque_ty_node_id, bounds, span);
visitor.collected_lifetimes
}

View File

@ -1146,6 +1146,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
// don't create labels for compiler-generated spans
Some(_) => None,
// don't create labels for the span not from user's code
None if opt_assignment_rhs_span
.is_some_and(|span| self.infcx.tcx.sess.source_map().is_imported(span)) =>
{
None
}
None => {
let (has_sugg, decl_span, sugg) = if name != kw::SelfLower {
suggest_ampmut(
@ -1198,18 +1204,21 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
sugg.push(s);
}
err.multipart_suggestion_verbose(
format!(
"consider changing this to be a mutable {pointer_desc}{}",
if is_trait_sig {
" in the `impl` method and the `trait` definition"
} else {
""
}
),
sugg,
Applicability::MachineApplicable,
);
if sugg.iter().all(|(span, _)| !self.infcx.tcx.sess.source_map().is_imported(*span))
{
err.multipart_suggestion_verbose(
format!(
"consider changing this to be a mutable {pointer_desc}{}",
if is_trait_sig {
" in the `impl` method and the `trait` definition"
} else {
""
}
),
sugg,
Applicability::MachineApplicable,
);
}
}
Some((false, err_label_span, message, _)) => {
let def_id = self.body.source.def_id();

View File

@ -8,6 +8,7 @@ use fluent_syntax::ast::{
Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement,
};
use fluent_syntax::parser::ParserError;
use proc_macro::tracked_path::path;
use proc_macro::{Diagnostic, Level, Span};
use proc_macro2::TokenStream;
use quote::quote;
@ -99,8 +100,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
let crate_name = Ident::new(&crate_name, resource_str.span());
// As this macro also outputs an `include_str!` for this file, the macro will always be
// re-executed when the file changes.
path(absolute_ftl_path.to_str().unwrap());
let resource_contents = match read_to_string(absolute_ftl_path) {
Ok(resource_contents) => resource_contents,
Err(e) => {

View File

@ -6,6 +6,7 @@
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
#![feature(rustdoc_internals)]
#![feature(track_path)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end

View File

@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use crate::hir_ty_lowering::OnlySelfBounds;
use crate::hir_ty_lowering::PredicateFilter;
/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
@ -52,7 +52,7 @@ impl<'tcx> Bounds<'tcx> {
span: Span,
polarity: ty::PredicatePolarity,
constness: ty::BoundConstness,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) {
let clause = (
bound_trait_ref
@ -72,9 +72,18 @@ impl<'tcx> Bounds<'tcx> {
// FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
// Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
// type bounds.
if !tcx.features().effects || only_self_bounds.0 {
if !tcx.features().effects {
return;
}
match predicate_filter {
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
return;
}
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
// Ok.
}
}
// For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
// associated type of `<T as Tr>` and make sure that the effect is compatible.
let compat_val = match (tcx.def_kind(defining_def_id), constness) {

View File

@ -16,7 +16,7 @@ use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
use crate::delegation::inherit_predicates_for_delegation_item;
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
@ -270,7 +270,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bound_pred.bounds.iter(),
&mut bounds,
bound_vars,
OnlySelfBounds(false),
PredicateFilter::All,
);
predicates.extend(bounds.clauses(tcx));
effects_min_tys.extend(bounds.effects_min_tys());
@ -825,20 +825,6 @@ impl<'tcx> ItemCtxt<'tcx> {
continue;
};
// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
// want to only consider predicates with `Self: ...`, but we don't want
// `OnlySelfBounds(true)` since we want to collect the nested associated
// type bound as well.
let (only_self_bounds, assoc_name) = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
(OnlySelfBounds(false), None)
}
PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
PredicateFilter::SelfThatDefines(assoc_name) => {
(OnlySelfBounds(true), Some(assoc_name))
}
};
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
ty
} else if matches!(filter, PredicateFilter::All) {
@ -850,31 +836,13 @@ impl<'tcx> ItemCtxt<'tcx> {
let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
self.lowerer().lower_poly_bounds(
bound_ty,
predicate.bounds.iter().filter(|bound| {
assoc_name
.map_or(true, |assoc_name| self.bound_defines_assoc_item(bound, assoc_name))
}),
predicate.bounds.iter(),
&mut bounds,
bound_vars,
only_self_bounds,
filter,
);
}
bounds.clauses(self.tcx).collect()
}
#[instrument(level = "trace", skip(self))]
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
match b {
hir::GenericBound::Trait(poly_trait_ref) => {
let trait_ref = &poly_trait_ref.trait_ref;
if let Some(trait_did) = trait_ref.trait_def_id() {
self.tcx.trait_may_define_assoc_item(trait_did, assoc_name)
} else {
false
}
}
_ => false,
}
}
}

View File

@ -19,9 +19,7 @@ use tracing::{debug, instrument};
use super::errors::GenericsArgsErrExtend;
use crate::bounds::Bounds;
use crate::errors;
use crate::hir_ty_lowering::{
AssocItemQSelf, HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason,
};
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer, PredicateFilter, RegionInferReason};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Add a `Sized` bound to the `bounds` if appropriate.
@ -150,11 +148,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_bounds: I,
bounds: &mut Bounds<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) where
'tcx: 'hir,
{
for hir_bound in hir_bounds {
// In order to avoid cycles, when we're lowering `SelfThatDefines`,
// we skip over any traits that don't define the given associated type.
if let PredicateFilter::SelfThatDefines(assoc_name) = predicate_filter {
if let Some(trait_ref) = hir_bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
// Okay
} else {
continue;
}
}
match hir_bound {
hir::GenericBound::Trait(poly_trait_ref) => {
let (constness, polarity) = match poly_trait_ref.modifiers {
@ -179,7 +191,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
polarity,
param_ty,
bounds,
only_self_bounds,
predicate_filter,
);
}
hir::GenericBound::Outlives(lifetime) => {
@ -213,37 +225,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
param_ty: Ty<'tcx>,
hir_bounds: &[hir::GenericBound<'tcx>],
filter: PredicateFilter,
predicate_filter: PredicateFilter,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
let only_self_bounds = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
OnlySelfBounds(false)
}
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
};
self.lower_poly_bounds(
param_ty,
hir_bounds.iter().filter(|bound| match filter {
PredicateFilter::All
| PredicateFilter::SelfOnly
| PredicateFilter::SelfAndAssociatedTypeBounds => true,
PredicateFilter::SelfThatDefines(assoc_name) => {
if let Some(trait_ref) = bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
&& self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
true
} else {
false
}
}
}),
hir_bounds.iter(),
&mut bounds,
ty::List::empty(),
only_self_bounds,
predicate_filter,
);
debug!(?bounds);
@ -267,7 +258,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
bounds: &mut Bounds<'tcx>,
duplicates: &mut FxIndexMap<DefId, Span>,
path_span: Span,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
@ -444,21 +435,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
// to a bound involving a projection: `<T as Iterator>::Item: Debug`.
hir::AssocItemConstraintKind::Bound { bounds: hir_bounds } => {
// NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into
// a trait predicate, since we only want to add predicates for the `Self` type.
if !only_self_bounds.0 {
let projection_ty = projection_term
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
self.lower_poly_bounds(
param_ty,
hir_bounds.iter(),
bounds,
projection_ty.bound_vars(),
only_self_bounds,
);
match predicate_filter {
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {}
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
let projection_ty = projection_term
.map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
// Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty =
Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
self.lower_poly_bounds(
param_ty,
hir_bounds.iter(),
bounds,
projection_ty.bound_vars(),
predicate_filter,
);
}
}
}
}
@ -516,7 +509,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
trait_segment,
false,
ty::BoundConstness::NotConst,
);
// SUBTLE: As noted at the end of `try_append_return_type_notation_params`

View File

@ -20,7 +20,7 @@ use tracing::{debug, instrument};
use super::HirTyLowerer;
use crate::bounds::Bounds;
use crate::hir_ty_lowering::{
GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
@ -55,9 +55,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::PredicatePolarity::Positive,
dummy_self,
&mut bounds,
// True so we don't populate `bounds` with associated type bounds, even
// though they're disallowed from object types.
OnlySelfBounds(true),
PredicateFilter::SelfOnly,
) {
potential_assoc_types.extend(cur_potential_assoc_types);
}

View File

@ -64,9 +64,6 @@ use crate::require_c_abi_if_c_variadic;
#[derive(Debug)]
pub struct GenericPathSegment(pub DefId, pub usize);
#[derive(Copy, Clone, Debug)]
pub struct OnlySelfBounds(pub bool);
#[derive(Copy, Clone, Debug)]
pub enum PredicateFilter {
/// All predicates may be implied by the trait.
@ -76,7 +73,8 @@ pub enum PredicateFilter {
SelfOnly,
/// Only traits that reference `Self: ..` and define an associated type
/// with the given ident are implied by the trait.
/// with the given ident are implied by the trait. This mode exists to
/// side-step query cycles when lowering associated types.
SelfThatDefines(Ident),
/// Only traits that reference `Self: ..` and their associated type bounds.
@ -336,14 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
) -> GenericArgsRef<'tcx> {
let (args, _) = self.lower_generic_args_of_path(
span,
def_id,
&[],
item_segment,
None,
ty::BoundConstness::NotConst,
);
let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None);
if let Some(c) = item_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
}
@ -392,7 +383,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
parent_args: &[ty::GenericArg<'tcx>],
segment: &hir::PathSegment<'tcx>,
self_ty: Option<Ty<'tcx>>,
constness: ty::BoundConstness,
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
@ -415,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assert!(self_ty.is_none());
}
let mut arg_count = check_generic_arg_count(
let arg_count = check_generic_arg_count(
self,
def_id,
segment,
@ -573,16 +563,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
}
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
&& !tcx.is_const_trait(def_id)
{
let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
});
arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
}
let mut args_ctx = GenericArgsCtxt {
lowerer: self,
@ -614,14 +594,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
parent_args: GenericArgsRef<'tcx>,
) -> GenericArgsRef<'tcx> {
debug!(?span, ?item_def_id, ?item_segment);
let (args, _) = self.lower_generic_args_of_path(
span,
item_def_id,
parent_args,
item_segment,
None,
ty::BoundConstness::NotConst,
);
let (args, _) =
self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None);
if let Some(c) = item_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
}
@ -647,7 +621,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
ty::BoundConstness::NotConst,
)
}
@ -683,7 +656,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
polarity: ty::PredicatePolarity,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
only_self_bounds: OnlySelfBounds,
predicate_filter: PredicateFilter,
) -> GenericArgCountResult {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
@ -700,9 +673,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[],
trait_segment,
Some(self_ty),
constness,
);
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
&& !self.tcx().is_const_trait(trait_def_id)
{
self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span: trait_ref.path.span,
modifier: constness.as_str(),
});
}
let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
debug!(?bound_vars);
@ -720,7 +701,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span,
polarity,
constness,
only_self_bounds,
predicate_filter,
);
let mut dup_constraints = FxIndexMap::default();
@ -744,7 +725,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
bounds,
&mut dup_constraints,
constraint.span,
only_self_bounds,
predicate_filter,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
@ -762,19 +743,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'tcx>,
is_impl: bool,
// FIXME(effects): Move all host param things in HIR ty lowering to AST lowering.
constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
let (generic_args, _) = self.lower_generic_args_of_path(
span,
trait_def_id,
&[],
trait_segment,
Some(self_ty),
constness,
);
let (generic_args, _) =
self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty));
if let Some(c) = trait_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
}
@ -1542,7 +1515,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
constness: ty::BoundConstness,
) -> Ty<'tcx> {
let tcx = self.tcx();
@ -1555,7 +1527,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?self_ty);
let trait_ref =
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false, constness);
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
debug!(?trait_ref);
let item_args =
@ -1918,7 +1890,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
def_id,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
ty::BoundConstness::NotConst,
)
}
Res::PrimTy(prim_ty) => {
@ -2151,7 +2122,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[],
&hir::PathSegment::invalid(),
None,
ty::BoundConstness::NotConst,
);
tcx.at(span).type_of(def_id).instantiate(tcx, args)
}

View File

@ -18,6 +18,8 @@ use rustc_target::spec::abi::Abi as SpecAbi;
use tracing::debug;
use {rustc_ast as ast, rustc_hir as hir};
mod improper_ctypes;
use crate::lints::{
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
@ -983,15 +985,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_non_exhaustive,
help: None,
};
}
// Check for a repr() attribute to specify the size of the
// discriminant.
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
@ -1010,21 +1003,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}
use improper_ctypes::{
check_non_exhaustive_variant, non_local_and_non_exhaustive,
};
let non_local_def = non_local_and_non_exhaustive(def);
// Check the contained variants.
for variant in def.variants() {
let is_non_exhaustive = variant.is_field_list_non_exhaustive();
if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_non_exhaustive_variant,
help: None,
};
}
let ret = def.variants().iter().try_for_each(|variant| {
check_non_exhaustive_variant(non_local_def, variant)
.map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
match self.check_variant_for_ffi(acc, ty, def, variant, args) {
FfiSafe => (),
r => return r,
FfiSafe => ControlFlow::Continue(()),
r => ControlFlow::Break(r),
}
});
if let ControlFlow::Break(result) = ret {
return result;
}
FfiSafe

View File

@ -0,0 +1,51 @@
use std::ops::ControlFlow;
use rustc_errors::DiagMessage;
use rustc_hir::def::CtorKind;
use rustc_middle::ty;
use crate::fluent_generated as fluent;
/// Check a variant of a non-exhaustive enum for improper ctypes
///
/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
/// This includes linting, on a best-effort basis. There are valid additions that are unlikely.
///
/// Adding a data-carrying variant to an existing C-like enum that is passed to C is "unlikely",
/// so we don't need the lint to account for it.
/// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }.
pub(crate) fn check_non_exhaustive_variant(
non_local_def: bool,
variant: &ty::VariantDef,
) -> ControlFlow<DiagMessage, ()> {
// non_exhaustive suggests it is possible that someone might break ABI
// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
// so warn on complex enums being used outside their crate
if non_local_def {
// which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195
// with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
// but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
if variant_has_complex_ctor(variant) {
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive);
}
}
let non_exhaustive_variant_fields = variant.is_field_list_non_exhaustive();
if non_exhaustive_variant_fields && !variant.def_id.is_local() {
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant);
}
ControlFlow::Continue(())
}
fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
// CtorKind::Const means a "unit" ctor
!matches!(variant.ctor_kind(), Some(CtorKind::Const))
}
// non_exhaustive suggests it is possible that someone might break ABI
// see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
// so warn on complex enums being used outside their crate
pub(crate) fn non_local_and_non_exhaustive(def: ty::AdtDef<'_>) -> bool {
def.is_variant_list_non_exhaustive() && !def.did().is_local()
}

View File

@ -1277,19 +1277,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let normalized_term =
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
let is_normalized_term_expected = !matches!(
obligation.cause.code().peel_derives(),
ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..)
| ObligationCauseCode::Coercion { .. }
);
let (expected, actual) = if is_normalized_term_expected {
(normalized_term, data.term)
} else {
(data.term, normalized_term)
};
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
//
@ -1298,12 +1285,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let _ = ocx.select_where_possible();
if let Err(new_err) =
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
ocx.eq(&obligation.cause, obligation.param_env, data.term, normalized_term)
{
(
Some((
data.projection_term,
is_normalized_term_expected,
false,
self.resolve_vars_if_possible(normalized_term),
data.term,
)),
@ -1444,12 +1431,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&mut diag,
&obligation.cause,
secondary_span,
values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
expected_ty,
))
values.map(|(_, _, normalized_ty, expected_ty)| {
infer::ValuePairs::Terms(ExpectedFound::new(true, expected_ty, normalized_ty))
}),
err,
false,

View File

@ -18,17 +18,10 @@ macro_rules! define_client_handles {
$(pub(super) $ity: AtomicU32,)*
}
impl HandleCounters {
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
extern "C" fn get() -> &'static Self {
static COUNTERS: HandleCounters = HandleCounters {
$($oty: AtomicU32::new(1),)*
$($ity: AtomicU32::new(1),)*
};
&COUNTERS
}
}
static COUNTERS: HandleCounters = HandleCounters {
$($oty: AtomicU32::new(1),)*
$($ity: AtomicU32::new(1),)*
};
$(
pub(crate) struct $oty {
@ -259,9 +252,7 @@ pub(crate) fn is_available() -> bool {
/// and forcing the use of APIs that take/return `S::TokenStream`, server-side.
#[repr(C)]
pub struct Client<I, O> {
// FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
// a wrapper `fn` pointer, once `const fn` can reference `static`s.
pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
pub(super) handle_counters: &'static HandleCounters,
pub(super) run: extern "C" fn(BridgeConfig<'_>) -> Buffer,
@ -346,7 +337,7 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
impl Client<crate::TokenStream, crate::TokenStream> {
pub const fn expand1(f: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy) -> Self {
Client {
get_handle_counters: HandleCounters::get,
handle_counters: &COUNTERS,
run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| {
run_client(bridge, |input| f(crate::TokenStream(Some(input))).0)
}),
@ -360,7 +351,7 @@ impl Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> {
f: impl Fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + Copy,
) -> Self {
Client {
get_handle_counters: HandleCounters::get,
handle_counters: &COUNTERS,
run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| {
run_client(bridge, |(input, input2)| {
f(crate::TokenStream(Some(input)), crate::TokenStream(Some(input2))).0

View File

@ -400,10 +400,10 @@ impl client::Client<crate::TokenStream, crate::TokenStream> {
S: Server,
S::TokenStream: Default,
{
let client::Client { get_handle_counters, run, _marker } = *self;
let client::Client { handle_counters, run, _marker } = *self;
run_server(
strategy,
get_handle_counters(),
handle_counters,
server,
<MarkedTypes<S> as Types>::TokenStream::mark(input),
run,
@ -426,10 +426,10 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream
S: Server,
S::TokenStream: Default,
{
let client::Client { get_handle_counters, run, _marker } = *self;
let client::Client { handle_counters, run, _marker } = *self;
run_server(
strategy,
get_handle_counters(),
handle_counters,
server,
(
<MarkedTypes<S> as Types>::TokenStream::mark(input),

View File

@ -189,7 +189,7 @@ cfg_has_statx! {{
// See: https://github.com/rust-lang/rust/issues/65662
//
// FIXME what about transient conditions like `ENOMEM`?
let err2 = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut()))
let err2 = cvt(statx(0, ptr::null(), 0, libc::STATX_BASIC_STATS | libc::STATX_BTIME, ptr::null_mut()))
.err()
.and_then(|e| e.raw_os_error());
if err2 == Some(libc::EFAULT) {
@ -910,7 +910,7 @@ impl DirEntry {
fd,
name,
libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT,
libc::STATX_ALL,
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
) } {
return ret;
}
@ -1194,7 +1194,7 @@ impl File {
fd,
c"".as_ptr() as *const c_char,
libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT,
libc::STATX_ALL,
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
) } {
return ret;
}
@ -1767,7 +1767,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
libc::AT_FDCWD,
p.as_ptr(),
libc::AT_STATX_SYNC_AS_STAT,
libc::STATX_ALL,
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
) } {
return ret;
}
@ -1786,7 +1786,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
libc::AT_FDCWD,
p.as_ptr(),
libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT,
libc::STATX_ALL,
libc::STATX_BASIC_STATS | libc::STATX_BTIME,
) } {
return ret;
}

View File

@ -6,9 +6,12 @@ edition = "2021"
[lib]
path = "lib.rs"
[features]
default = ["rustc-hash"]
[dependencies]
serde = { version = "1.0", features = ["derive"] }
rustc-hash = "1.1.0"
rustc-hash = { version = "1.1.0", optional = true }
[dev-dependencies]
serde_json = "1.0"

View File

@ -3,11 +3,16 @@
//! These types are the public API exposed through the `--output-format json` flag. The [`Crate`]
//! struct is the root of the JSON blob and all other items are contained within.
#[cfg(not(feature = "rustc-hash"))]
use std::collections::HashMap;
use std::path::PathBuf;
pub use rustc_hash::FxHashMap;
#[cfg(feature = "rustc-hash")]
use rustc_hash::FxHashMap as HashMap;
use serde::{Deserialize, Serialize};
pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
/// The version of JSON output that this crate represents.
///
/// This integer is incremented with every breaking change to the API,
@ -30,11 +35,11 @@ pub struct Crate {
pub includes_private: bool,
/// A collection of all items in the local crate as well as some external traits and their
/// items that are referenced locally.
pub index: FxHashMap<Id, Item>,
pub index: HashMap<Id, Item>,
/// Maps IDs to fully qualified paths and other info helpful for generating links.
pub paths: FxHashMap<Id, ItemSummary>,
pub paths: HashMap<Id, ItemSummary>,
/// Maps `crate_id` of items to a crate name and html_root_url if it exists.
pub external_crates: FxHashMap<u32, ExternalCrate>,
pub external_crates: HashMap<u32, ExternalCrate>,
/// A single version number to be used in the future when making backwards incompatible changes
/// to the JSON output.
pub format_version: u32,
@ -95,7 +100,7 @@ pub struct Item {
/// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`).
pub docs: Option<String>,
/// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
pub links: FxHashMap<String, Id>,
pub links: HashMap<String, Id>,
/// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
pub attrs: Vec<String>,
/// Information about the items deprecation, if present.

View File

@ -468,7 +468,19 @@ impl<'test> TestCx<'test> {
if let Some(revision) = self.revision {
let normalized_revision = normalize_revision(revision);
cmd.args(&["--cfg", &normalized_revision]);
let cfg_arg = ["--cfg", &normalized_revision];
let arg = format!("--cfg={normalized_revision}");
if self
.props
.compile_flags
.windows(2)
.any(|args| args == cfg_arg || args[0] == arg || args[1] == arg)
{
panic!(
"error: redundant cfg argument `{normalized_revision}` is already created by the revision"
);
}
cmd.args(cfg_arg);
}
if !self.props.no_auto_check_cfg {

View File

@ -0,0 +1,27 @@
//@ compile-flags: -O -Zmerge-functions=disabled
//! Test for <https://github.com/rust-lang/rust/issues/108395>. Check that
//! matching on two bools with wildcards does not produce branches.
#![crate_type = "lib"]
// CHECK-LABEL: @wildcard(
#[no_mangle]
pub fn wildcard(a: u16, b: u16, v: u16) -> u16 {
// CHECK-NOT: br
match (a == v, b == v) {
(true, false) => 0,
(false, true) => u16::MAX,
_ => 1 << 15, // half
}
}
// CHECK-LABEL: @exhaustive(
#[no_mangle]
pub fn exhaustive(a: u16, b: u16, v: u16) -> u16 {
// CHECK-NOT: br
match (a == v, b == v) {
(true, false) => 0,
(false, true) => u16::MAX,
(true, true) => 1 << 15,
(false, false) => 1 << 15,
}
}

View File

@ -2,18 +2,16 @@ error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
--> $DIR/impl-trait-return-missing-constraint.rs:25:13
|
LL | fn bar() -> impl Bar {
| -------- the expected opaque type
| -------- the found opaque type
...
LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
| ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
LL |
LL | bar()
| ----- return type was inferred to be `impl Bar` here
|
= note: expected associated type `<impl Bar as Foo>::Item`
found type `i32`
= help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
= note: expected type `i32`
found associated type `<impl Bar as Foo>::Item`
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
LL | fn bar() -> impl Bar<Item = i32> {

View File

@ -22,10 +22,10 @@ error[E0271]: type mismatch resolving `<{coroutine@$DIR/type-mismatch-signature-
--> $DIR/type-mismatch-signature-deduction.rs:5:13
|
LL | fn foo() -> impl Coroutine<Return = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<{integer}, _>`, found `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `Result<{integer}, _>`
|
= note: expected enum `Result<{integer}, _>`
found type `i32`
= note: expected type `i32`
found enum `Result<{integer}, _>`
error: aborting due to 2 previous errors

View File

@ -29,10 +29,7 @@ error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Tex
--> $DIR/as_expression.rs:57:5
|
LL | SelectInt.check("bar");
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Integer`, found `Text`
|
= note: expected struct `Integer`
found struct `Text`
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
error: aborting due to 3 previous errors

View File

@ -7,13 +7,13 @@ LL |
LL | Foo(())
| ------- return type was inferred to be `Foo<()>` here
|
note: expected this to be `()`
note: expected this to be `<T as impl_trait::Trait>::Assoc`
--> $DIR/bound-normalization-fail.rs:14:19
|
LL | type Output = T;
| ^
= note: expected unit type `()`
found associated type `<T as impl_trait::Trait>::Assoc`
= note: expected associated type `<T as impl_trait::Trait>::Assoc`
found unit type `()`
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
|
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {
@ -28,13 +28,13 @@ LL |
LL | Foo(())
| ------- return type was inferred to be `Foo<()>` here
|
note: expected this to be `()`
note: expected this to be `<T as lifetimes::Trait<'a>>::Assoc`
--> $DIR/bound-normalization-fail.rs:14:19
|
LL | type Output = T;
| ^
= note: expected unit type `()`
found associated type `<T as lifetimes::Trait<'a>>::Assoc`
= note: expected associated type `<T as lifetimes::Trait<'a>>::Assoc`
found unit type `()`
help: consider constraining the associated type `<T as lifetimes::Trait<'a>>::Assoc` to `()`
|
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output = T::Assoc> {

View File

@ -2,7 +2,7 @@ error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String`
--> $DIR/default-body-type-err.rs:4:22
|
LL | fn lol(&self) -> impl Deref<Target = String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `i32`
LL |
LL | &1i32
| ----- return type was inferred to be `&i32` here

View File

@ -16,7 +16,7 @@ error[E0271]: expected `{async block@$DIR/issue-78722-2.rs:13:13: 13:18}` to be
--> $DIR/issue-78722-2.rs:11:30
|
LL | fn concrete_use() -> F {
| ^ expected `()`, found `u8`
| ^ expected `u8`, found `()`
error: aborting due to 2 previous errors

View File

@ -12,7 +12,7 @@ error[E0271]: expected `{async block@$DIR/issue-78722.rs:10:13: 10:18}` to be a
--> $DIR/issue-78722.rs:8:30
|
LL | fn concrete_use() -> F {
| ^ expected `()`, found `u8`
| ^ expected `u8`, found `()`
error: aborting due to 2 previous errors

View File

@ -0,0 +1,15 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![feature(rustc_attrs)]
#![feature(type_alias_impl_trait)]
#![rustc_variance_of_opaques]
fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
//~^ ERROR ['_: o]
//~| ERROR ['_: o]
//~| ERROR `impl Trait` captures lifetime parameter
[*x]
}
fn main() {}

View File

@ -0,0 +1,22 @@
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
--> $DIR/capturing-implicit.rs:8:11
|
LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
| ^ -------------------------------------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
| |
| this lifetime parameter is captured
error: ['_: o]
--> $DIR/capturing-implicit.rs:8:19
|
LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: ['_: o]
--> $DIR/capturing-implicit.rs:8:44
|
LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
| ^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -4,7 +4,7 @@ error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()`
LL | fn test() -> impl Test {
| ^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == ()`
|
note: expected this to be `u8`
note: expected this to be `()`
--> $DIR/projection-mismatch-in-impl-where-clause.rs:6:18
|
LL | type Assoc = u8;

View File

@ -20,10 +20,10 @@ error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(&_, &_)`, found `&_`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)`
|
= note: expected tuple `(&_, &_)`
found reference `&_`
= note: expected reference `&_`
found tuple `(&_, &_)`
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator`
= note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator`

View File

@ -2,10 +2,10 @@ error[E0271]: type mismatch resolving `<Rc<Apple> as Deref>::Target == Rc<Apple>
--> $DIR/issue-67039-unsound-pin-partialeq.rs:25:29
|
LL | let _ = Pin::new(Apple) == Rc::pin(Apple);
| ^^ expected `Apple`, found `Rc<Apple>`
| ^^ expected `Rc<Apple>`, found `Apple`
|
= note: expected struct `Apple`
found struct `Rc<Apple>`
= note: expected struct `Rc<Apple>`
found struct `Apple`
= note: required for `Pin<Apple>` to implement `PartialEq<Pin<Rc<Apple>>>`
error: aborting due to 1 previous error

View File

@ -2,7 +2,7 @@ error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns
--> $DIR/issue-106991.rs:5:13
|
LL | fn bar() -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
|
= note: required for `Map<std::slice::IterMut<'_, Vec<u8>>, for<'a> fn(&'a mut Vec<u8>) {foo}>` to implement `Iterator`

View File

@ -2,8 +2,6 @@
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
//@ error-pattern: unsafe precondition(s) violated: Layout::from_size_align_unchecked requires
//@ revisions: toolarge badalign
//@[toolarge] compile-flags: --cfg toolarge
//@[badalign] compile-flags: --cfg badalign
fn main() {
unsafe {

View File

@ -27,3 +27,14 @@ pub enum NonExhaustiveVariants {
#[non_exhaustive] Tuple(u32),
#[non_exhaustive] Struct { field: u32 }
}
// Note the absence of repr(C): it's not necessary, and recent C code can now use repr hints too.
#[repr(u32)]
#[non_exhaustive]
pub enum NonExhaustiveCLikeEnum {
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
}

View File

@ -6,7 +6,10 @@ extern crate types;
// This test checks that non-exhaustive types with `#[repr(C)]` from an extern crate are considered
// improper.
use types::{NonExhaustiveEnum, NonExhaustiveVariants, NormalStruct, TupleStruct, UnitStruct};
use types::{
NonExhaustiveCLikeEnum, NonExhaustiveEnum, NonExhaustiveVariants,
NormalStruct, TupleStruct, UnitStruct,
};
extern "C" {
pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
@ -21,4 +24,9 @@ extern "C" {
//~^ ERROR `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe
}
// These should pass without remark, as they're C-compatible, despite being "non-exhaustive".
extern "C" {
pub fn non_exhaustive_c_compat_enum(_: NonExhaustiveCLikeEnum);
}
fn main() {}

View File

@ -1,5 +1,5 @@
error: `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:12:35
--> $DIR/extern_crate_improper.rs:15:35
|
LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum);
| ^^^^^^^^^^^^^^^^^ not FFI-safe
@ -12,7 +12,7 @@ LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `NormalStruct`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:14:44
--> $DIR/extern_crate_improper.rs:17:44
|
LL | pub fn non_exhaustive_normal_struct(_: NormalStruct);
| ^^^^^^^^^^^^ not FFI-safe
@ -20,7 +20,7 @@ LL | pub fn non_exhaustive_normal_struct(_: NormalStruct);
= note: this struct is non-exhaustive
error: `extern` block uses type `UnitStruct`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:16:42
--> $DIR/extern_crate_improper.rs:19:42
|
LL | pub fn non_exhaustive_unit_struct(_: UnitStruct);
| ^^^^^^^^^^ not FFI-safe
@ -28,7 +28,7 @@ LL | pub fn non_exhaustive_unit_struct(_: UnitStruct);
= note: this struct is non-exhaustive
error: `extern` block uses type `TupleStruct`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:18:43
--> $DIR/extern_crate_improper.rs:21:43
|
LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct);
| ^^^^^^^^^^^ not FFI-safe
@ -36,7 +36,7 @@ LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct);
= note: this struct is non-exhaustive
error: `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe
--> $DIR/extern_crate_improper.rs:20:38
--> $DIR/extern_crate_improper.rs:23:38
|
LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants);
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe

View File

@ -5,19 +5,19 @@
//@ revisions: address cfi kcfi leak memory thread
//@compile-flags: -Ctarget-feature=-crt-static
//@[address]needs-sanitizer-address
//@[address]compile-flags: -Zsanitizer=address --cfg address
//@[address]compile-flags: -Zsanitizer=address
//@[cfi]needs-sanitizer-cfi
//@[cfi]compile-flags: -Zsanitizer=cfi --cfg cfi
//@[cfi]compile-flags: -Zsanitizer=cfi
//@[cfi]compile-flags: -Clto -Ccodegen-units=1
//@[kcfi]needs-llvm-components: x86
//@[kcfi]compile-flags: -Zsanitizer=kcfi --cfg kcfi --target x86_64-unknown-none
//@[kcfi]compile-flags: -Zsanitizer=kcfi --target x86_64-unknown-none
//@[kcfi]compile-flags: -C panic=abort
//@[leak]needs-sanitizer-leak
//@[leak]compile-flags: -Zsanitizer=leak --cfg leak
//@[leak]compile-flags: -Zsanitizer=leak
//@[memory]needs-sanitizer-memory
//@[memory]compile-flags: -Zsanitizer=memory --cfg memory
//@[memory]compile-flags: -Zsanitizer=memory
//@[thread]needs-sanitizer-thread
//@[thread]compile-flags: -Zsanitizer=thread --cfg thread
//@[thread]compile-flags: -Zsanitizer=thread
#![feature(cfg_sanitize, no_core, lang_items)]
#![crate_type="lib"]

View File

@ -4,7 +4,7 @@
// For some reason, Rust 2018 or higher is required to reproduce the bug.
//@ run-rustfix
//@ revisions: no_std std
//@ [no_std]compile-flags: --cfg=no_std -C panic=abort
//@ [no_std]compile-flags: -C panic=abort
#![cfg_attr(no_std, no_std)]
use core::num::NonZero;

View File

@ -4,7 +4,7 @@
// For some reason, Rust 2018 or higher is required to reproduce the bug.
//@ run-rustfix
//@ revisions: no_std std
//@ [no_std]compile-flags: --cfg=no_std -C panic=abort
//@ [no_std]compile-flags: -C panic=abort
#![cfg_attr(no_std, no_std)]
fn main() {

View File

@ -4,7 +4,7 @@
// For some reason, Rust 2018 or higher is required to reproduce the bug.
//@ run-rustfix
//@ revisions: no_std std
//@ [no_std]compile-flags: --cfg=no_std -C panic=abort
//@ [no_std]compile-flags: -C panic=abort
#![cfg_attr(no_std, no_std)]
use std::num::NonZero;

View File

@ -0,0 +1,7 @@
fn main() {
let val = 2;
let ptr = std::ptr::addr_of!(val);
unsafe {
*ptr = 3; //~ ERROR cannot assign to `*ptr`, which is behind a `*const` pointer
}
}

View File

@ -0,0 +1,9 @@
error[E0594]: cannot assign to `*ptr`, which is behind a `*const` pointer
--> $DIR/dont_suggest_raw_pointer_syntax-issue-127562.rs:5:9
|
LL | *ptr = 3;
| ^^^^^^^^ `ptr` is a `*const` pointer, so the data it refers to cannot be written
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0594`.

View File

@ -8,14 +8,14 @@ error[E0271]: expected `Box<dyn Iterator>` to be an iterator that yields `u32`,
--> $DIR/trait-hidden-method.rs:3:32
|
LL | pub fn i_can_has_iterator() -> impl Iterator<Item = u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `u32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found associated type
...
LL | Box::new(1..=10) as Box<dyn Iterator>
| ------------------------------------- return type was inferred to be `Box<dyn Iterator>` here
|
= note: expected associated type `<dyn Iterator as Iterator>::Item`
found type `u32`
= help: consider constraining the associated type `<dyn Iterator as Iterator>::Item` to `u32` or calling a method that returns `<dyn Iterator as Iterator>::Item`
= note: expected type `u32`
found associated type `<dyn Iterator as Iterator>::Item`
= help: consider constraining the associated type `<dyn Iterator as Iterator>::Item` to `u32`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error: aborting due to 2 previous errors

View File

@ -2,12 +2,10 @@ error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future
--> $DIR/async.rs:12:17
|
LL | needs_async(async {});
| ----------- ^^^^^^^^ expected `()`, found `i32`
| ----------- ^^^^^^^^ expected `i32`, found `()`
| |
| required by a bound introduced by this call
|
= note: expected unit type `()`
found type `i32`
note: required by a bound in `needs_async`
--> $DIR/async.rs:8:31
|

View File

@ -2,19 +2,14 @@ error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::
--> $DIR/more-object-bound.rs:12:5
|
LL | fn transmute<A, B>(x: A) -> B {
| - -
| | |
| | expected type parameter
| | found type parameter
| - - expected type parameter
| |
| found type parameter
| expected type parameter
LL | foo::<A, B, dyn Trait<A = A, B = B>>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `A`, found type parameter `B`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A`
|
= note: expected type parameter `A`
found type parameter `B`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
= note: expected type parameter `B`
found type parameter `A`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
= note: required because it appears within the type `dyn Trait<A = A, B = B>`

View File

@ -15,13 +15,13 @@ error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str
--> $DIR/try-block-bad-type.rs:12:9
|
LL | ""
| ^^ expected `i32`, found `&str`
| ^^ expected `&str`, found `i32`
error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()`
--> $DIR/try-block-bad-type.rs:15:39
|
LL | let res: Result<i32, i32> = try { };
| ^ expected `i32`, found `()`
| ^ expected `()`, found `i32`
error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
--> $DIR/try-block-bad-type.rs:17:25

View File

@ -2,18 +2,13 @@ error[E0271]: type mismatch resolving `<Option<f32> as Try>::Output == {integer}
--> $DIR/try-block-type-error.rs:10:9
|
LL | 42
| ^^ expected `f32`, found integer
|
help: use a float literal
|
LL | 42.0
| ++
| ^^ expected integer, found `f32`
error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()`
--> $DIR/try-block-type-error.rs:16:5
|
LL | };
| ^ expected `i32`, found `()`
| ^ expected `()`, found `i32`
error: aborting due to 2 previous errors

View File

@ -2,18 +2,18 @@ error[E0271]: type mismatch resolving `<() as Proj>::Assoc == i32`
--> $DIR/hidden_type_mismatch.rs:43:9
|
LL | pub type Sep = impl Sized + std::fmt::Display;
| ------------------------------ the expected opaque type
| ------------------------------ the found opaque type
...
LL | Bar { inner: 1i32, _marker: () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Proj>::Assoc == i32`
|
note: expected this to be `Sep`
note: expected this to be `i32`
--> $DIR/hidden_type_mismatch.rs:20:22
|
LL | type Assoc = sus::Sep;
| ^^^^^^^^
= note: expected opaque type `Sep`
found type `i32`
= note: expected type `i32`
found opaque type `Sep`
note: required for `Bar<()>` to implement `Copy`
--> $DIR/hidden_type_mismatch.rs:32:39
|

View File

@ -2,7 +2,7 @@ error[E0271]: type mismatch resolving `<{coroutine@$DIR/issue-94429.rs:18:9: 18:
--> $DIR/issue-94429.rs:15:26
|
LL | fn run(&mut self) -> Self::Coro {
| ^^^^^^^^^^ expected integer, found `()`
| ^^^^^^^^^^ expected `()`, found integer
error: aborting due to 1 previous error