2022-07-07 16:14:27 +02:00
|
|
|
use std::cell::LazyCell;
|
|
|
|
use std::ops::ControlFlow;
|
|
|
|
|
2024-10-27 20:38:33 -07:00
|
|
|
use rustc_abi::FieldIdx;
|
2025-02-09 22:49:33 +01:00
|
|
|
use rustc_attr_parsing::AttributeKind;
|
|
|
|
use rustc_attr_parsing::ReprAttr::ReprPacked;
|
2024-04-04 15:06:30 -04:00
|
|
|
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
2023-11-10 10:11:24 +08:00
|
|
|
use rustc_errors::MultiSpan;
|
2023-09-08 03:00:59 +00:00
|
|
|
use rustc_errors::codes::*;
|
|
|
|
use rustc_hir::def::{CtorKind, DefKind};
|
2025-02-06 20:08:29 +00:00
|
|
|
use rustc_hir::{LangItem, Node, intravisit};
|
2023-05-09 20:18:22 +00:00
|
|
|
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
2024-11-08 04:27:20 +00:00
|
|
|
use rustc_infer::traits::{Obligation, ObligationCauseCode};
|
2024-08-07 15:48:16 +02:00
|
|
|
use rustc_lint_defs::builtin::{
|
|
|
|
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
|
|
|
|
};
|
2024-11-08 03:46:23 +00:00
|
|
|
use rustc_middle::hir::nested_filter;
|
2024-04-04 12:54:56 -04:00
|
|
|
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
2022-04-27 18:14:19 +04:00
|
|
|
use rustc_middle::middle::stability::EvalResult;
|
2024-05-27 16:12:28 -04:00
|
|
|
use rustc_middle::ty::error::TypeErrorToStringExt;
|
2022-02-24 14:10:41 -05:00
|
|
|
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
2025-01-27 19:15:37 +00:00
|
|
|
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
2023-02-12 21:08:14 +00:00
|
|
|
use rustc_middle::ty::{
|
2025-03-13 18:05:00 +00:00
|
|
|
AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
|
|
|
|
TypeVisitable, TypeVisitableExt, fold_regions,
|
2023-02-12 21:08:14 +00:00
|
|
|
};
|
2024-09-03 18:48:15 +02:00
|
|
|
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
2024-07-21 15:20:41 -04:00
|
|
|
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
2024-07-08 15:36:57 -04:00
|
|
|
use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
|
2024-04-15 19:54:51 -04:00
|
|
|
use rustc_trait_selection::traits;
|
2025-02-06 20:08:29 +00:00
|
|
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
2024-08-30 09:02:58 +10:00
|
|
|
use tracing::{debug, instrument};
|
2024-10-18 00:28:43 +02:00
|
|
|
use ty::TypingMode;
|
2024-12-13 14:47:11 +01:00
|
|
|
use {rustc_attr_parsing as attr, rustc_hir as hir};
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2024-11-23 04:48:01 +00:00
|
|
|
use super::compare_impl_item::check_type_bounds;
|
2020-10-21 14:26:34 +02:00
|
|
|
use super::*;
|
|
|
|
|
2024-11-02 19:32:56 -07:00
|
|
|
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) {
|
2024-09-03 18:48:15 +02:00
|
|
|
if !tcx.sess.target.is_abi_supported(abi) {
|
|
|
|
struct_span_code_err!(
|
|
|
|
tcx.dcx(),
|
|
|
|
span,
|
|
|
|
E0570,
|
|
|
|
"`{abi}` is not a supported ABI for the current target",
|
|
|
|
)
|
|
|
|
.emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2024-08-07 15:48:16 +02:00
|
|
|
}
|
2021-01-24 17:15:05 +00:00
|
|
|
|
2024-11-02 19:32:56 -07:00
|
|
|
pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
|
2024-09-03 18:48:15 +02:00
|
|
|
if !tcx.sess.target.is_abi_supported(abi) {
|
|
|
|
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
|
|
|
lint.primary_message(format!(
|
|
|
|
"the calling convention {abi} is not supported on this target"
|
|
|
|
));
|
|
|
|
});
|
2021-01-24 17:15:05 +00:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2022-07-08 02:32:51 +00:00
|
|
|
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2020-09-19 13:51:59 -07:00
|
|
|
let def = tcx.adt_def(def_id);
|
2022-07-08 02:32:51 +00:00
|
|
|
let span = tcx.def_span(def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
def.destructor(tcx); // force the destructor to be evaluated
|
|
|
|
|
2022-03-05 07:28:41 +11:00
|
|
|
if def.repr().simd() {
|
2020-09-19 13:51:59 -07:00
|
|
|
check_simd(tcx, span, def_id);
|
|
|
|
}
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
check_transparent(tcx, def);
|
2020-09-19 13:51:59 -07:00
|
|
|
check_packed(tcx, span, def);
|
|
|
|
}
|
|
|
|
|
2022-07-08 02:32:51 +00:00
|
|
|
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2020-09-19 13:51:59 -07:00
|
|
|
let def = tcx.adt_def(def_id);
|
2022-07-08 02:32:51 +00:00
|
|
|
let span = tcx.def_span(def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
def.destructor(tcx); // force the destructor to be evaluated
|
2022-10-30 18:31:03 +00:00
|
|
|
check_transparent(tcx, def);
|
2020-09-19 13:51:59 -07:00
|
|
|
check_union_fields(tcx, span, def_id);
|
|
|
|
check_packed(tcx, span, def);
|
|
|
|
}
|
|
|
|
|
2024-10-27 01:35:33 +02:00
|
|
|
fn allowed_union_or_unsafe_field<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
typing_env: ty::TypingEnv<'tcx>,
|
|
|
|
span: Span,
|
|
|
|
) -> bool {
|
2025-02-06 20:08:29 +00:00
|
|
|
// HACK (not that bad of a hack don't worry): Some codegen tests don't even define proper
|
|
|
|
// impls for `Copy`. Let's short-circuit here for this validity check, since a lot of them
|
|
|
|
// use unions. We should eventually fix all the tests to define that lang item or use
|
|
|
|
// minicore stubs.
|
|
|
|
if ty.is_trivially_pure_clone_copy() {
|
|
|
|
return true;
|
2024-10-27 01:35:33 +02:00
|
|
|
}
|
2025-02-06 20:08:29 +00:00
|
|
|
// If `BikeshedGuaranteedNoDrop` is not defined in a `#[no_core]` test, fall back to `Copy`.
|
|
|
|
// This is an underapproximation of `BikeshedGuaranteedNoDrop`,
|
|
|
|
let def_id = tcx
|
|
|
|
.lang_items()
|
|
|
|
.get(LangItem::BikeshedGuaranteedNoDrop)
|
|
|
|
.unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span)));
|
|
|
|
let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else {
|
|
|
|
tcx.dcx().span_delayed_bug(span, "could not normalize field type");
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
|
|
|
|
infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
|
|
|
tcx,
|
|
|
|
ObligationCause::dummy_with_span(span),
|
|
|
|
param_env,
|
|
|
|
ty::TraitRef::new(tcx, def_id, [ty]),
|
|
|
|
))
|
2024-10-27 01:35:33 +02:00
|
|
|
}
|
|
|
|
|
2020-10-04 22:24:14 +02:00
|
|
|
/// Check that the fields of the `union` do not need dropping.
|
2020-10-24 16:13:39 +02:00
|
|
|
fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
|
2025-02-06 20:08:29 +00:00
|
|
|
let def = tcx.adt_def(item_def_id);
|
|
|
|
assert!(def.is_union());
|
|
|
|
|
|
|
|
let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
|
|
|
|
let args = ty::GenericArgs::identity_for_item(tcx, item_def_id);
|
2022-06-29 22:33:18 -04:00
|
|
|
|
2025-02-06 20:08:29 +00:00
|
|
|
for field in &def.non_enum_variant().fields {
|
|
|
|
if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) {
|
2025-02-03 10:45:49 +11:00
|
|
|
let (field_span, ty_span) = match tcx.hir_get_if_local(field.did) {
|
2025-02-06 20:08:29 +00:00
|
|
|
// We are currently checking the type this field came from, so it must be local.
|
|
|
|
Some(Node::Field(field)) => (field.span, field.ty.span),
|
|
|
|
_ => unreachable!("mir field has to correspond to hir field"),
|
|
|
|
};
|
|
|
|
tcx.dcx().emit_err(errors::InvalidUnionField {
|
|
|
|
field_span,
|
|
|
|
sugg: errors::InvalidUnionFieldSuggestion {
|
|
|
|
lo: ty_span.shrink_to_lo(),
|
|
|
|
hi: ty_span.shrink_to_hi(),
|
|
|
|
},
|
|
|
|
note: (),
|
|
|
|
});
|
|
|
|
return false;
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2025-02-06 20:08:29 +00:00
|
|
|
|
2020-09-19 13:51:59 -07:00
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2020-10-24 16:13:39 +02:00
|
|
|
/// Check that a `static` is inhabited.
|
2022-12-20 22:10:40 +01:00
|
|
|
fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2020-10-24 16:13:39 +02:00
|
|
|
// Make sure statics are inhabited.
|
|
|
|
// Other parts of the compiler assume that there are no uninhabited places. In principle it
|
2020-10-24 20:39:04 +02:00
|
|
|
// would be enough to check this for `extern` statics, as statics with an initializer will
|
2020-10-24 16:13:39 +02:00
|
|
|
// have UB during initialization if they are uninhabited, but there also seems to be no good
|
|
|
|
// reason to allow any statics to be uninhabited.
|
2023-07-11 22:35:29 +01:00
|
|
|
let ty = tcx.type_of(def_id).instantiate_identity();
|
2022-07-08 02:32:51 +00:00
|
|
|
let span = tcx.def_span(def_id);
|
2024-11-15 13:53:31 +01:00
|
|
|
let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
|
2022-02-24 14:10:41 -05:00
|
|
|
Ok(l) => l,
|
|
|
|
// Foreign statics that overflow their allowed size should emit an error
|
|
|
|
Err(LayoutError::SizeOverflow(_))
|
2024-03-11 17:47:45 +00:00
|
|
|
if matches!(tcx.def_kind(def_id), DefKind::Static{ .. }
|
2023-02-12 21:08:14 +00:00
|
|
|
if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
|
2022-02-24 14:10:41 -05:00
|
|
|
{
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().emit_err(errors::TooLargeStatic { span });
|
2022-02-24 14:10:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-02-19 00:44:45 +01:00
|
|
|
// Generic statics are rejected, but we still reach this case.
|
2022-02-24 14:10:41 -05:00
|
|
|
Err(e) => {
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().span_delayed_bug(span, format!("{e:?}"));
|
2022-02-24 14:10:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2020-10-24 16:13:39 +02:00
|
|
|
};
|
2024-10-27 21:34:49 -07:00
|
|
|
if layout.is_uninhabited() {
|
2024-01-16 16:14:33 +11:00
|
|
|
tcx.node_span_lint(
|
2020-10-24 16:13:39 +02:00
|
|
|
UNINHABITED_STATIC,
|
2023-11-24 19:28:19 +03:00
|
|
|
tcx.local_def_id_to_hir_id(def_id),
|
2020-10-24 16:13:39 +02:00
|
|
|
span,
|
|
|
|
|lint| {
|
2024-05-22 16:46:05 +02:00
|
|
|
lint.primary_message("static of uninhabited type");
|
2022-09-16 11:01:02 +04:00
|
|
|
lint
|
2023-12-08 01:52:56 +00:00
|
|
|
.note("uninhabited statics cannot be initialized, and any access would be an immediate error");
|
2020-10-24 16:13:39 +02:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-19 13:51:59 -07:00
|
|
|
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
|
|
|
|
/// projections that would result in "inheriting lifetimes".
|
2023-10-26 10:15:26 +00:00
|
|
|
fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2025-02-21 18:33:05 +11:00
|
|
|
let hir::OpaqueTy { origin, .. } = *tcx.hir_expect_opaque_ty(def_id);
|
2022-09-30 19:16:13 +00:00
|
|
|
|
|
|
|
// HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
|
|
|
|
// `async-std` (and `pub async fn` in general).
|
|
|
|
// Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
|
|
|
|
// See https://github.com/rust-lang/rust/issues/75100
|
|
|
|
if tcx.sess.opts.actually_rustdoc {
|
2020-09-07 10:01:45 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-09-30 19:16:13 +00:00
|
|
|
|
2024-08-09 20:43:30 -07:00
|
|
|
if tcx.type_of(def_id).instantiate_identity().references_error() {
|
2020-06-28 16:46:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2024-11-08 03:46:23 +00:00
|
|
|
if check_opaque_for_cycles(tcx, def_id).is_err() {
|
2022-09-30 19:16:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-06-27 23:13:39 +02:00
|
|
|
|
2024-11-08 03:46:23 +00:00
|
|
|
let _ = check_opaque_meets_bounds(tcx, def_id, origin);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-10-23 20:38:34 +00:00
|
|
|
|
2020-09-19 13:51:59 -07:00
|
|
|
/// Checks that an opaque type does not contain cycles.
|
|
|
|
pub(super) fn check_opaque_for_cycles<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
def_id: LocalDefId,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2023-11-08 06:56:06 +00:00
|
|
|
let args = GenericArgs::identity_for_item(tcx, def_id);
|
2023-11-13 02:08:14 +00:00
|
|
|
|
|
|
|
// First, try to look at any opaque expansion cycles, considering coroutine fields
|
|
|
|
// (even though these aren't necessarily true errors).
|
2025-01-27 19:15:37 +00:00
|
|
|
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
|
|
|
|
let reported = opaque_type_cycle_error(tcx, def_id);
|
|
|
|
return Err(reported);
|
2020-06-28 16:46:02 +01:00
|
|
|
}
|
2023-11-13 02:08:14 +00:00
|
|
|
|
|
|
|
Ok(())
|
2020-06-28 16:46:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
|
2020-07-02 21:45:28 +01:00
|
|
|
///
|
|
|
|
/// This is mostly checked at the places that specify the opaque type, but we
|
|
|
|
/// check those cases in the `param_env` of that function, which may have
|
|
|
|
/// bounds not on this opaque type:
|
|
|
|
///
|
2022-10-09 16:15:23 +02:00
|
|
|
/// ```ignore (illustrative)
|
|
|
|
/// type X<T> = impl Clone;
|
2020-07-02 21:45:28 +01:00
|
|
|
/// fn f<T: Clone>(t: T) -> X<T> {
|
|
|
|
/// t
|
|
|
|
/// }
|
2022-10-09 16:15:23 +02:00
|
|
|
/// ```
|
2020-07-02 21:45:28 +01:00
|
|
|
///
|
|
|
|
/// Without this check the above code is incorrectly accepted: we would ICE if
|
|
|
|
/// some tried, for example, to clone an `Option<X<&mut ()>>`.
|
2021-12-01 16:34:40 +00:00
|
|
|
#[instrument(level = "debug", skip(tcx))]
|
2020-06-28 16:46:02 +01:00
|
|
|
fn check_opaque_meets_bounds<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
def_id: LocalDefId,
|
2024-11-08 03:46:23 +00:00
|
|
|
origin: hir::OpaqueTyOrigin<LocalDefId>,
|
2023-06-27 23:13:39 +02:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2024-11-08 04:27:20 +00:00
|
|
|
let (span, definition_def_id) =
|
|
|
|
if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) {
|
|
|
|
(span, Some(def_id))
|
|
|
|
} else {
|
|
|
|
(tcx.def_span(def_id), None)
|
|
|
|
};
|
2024-11-08 03:46:23 +00:00
|
|
|
|
|
|
|
let defining_use_anchor = match origin {
|
2024-10-02 22:21:37 -04:00
|
|
|
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
|
|
|
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
|
2024-10-02 22:04:18 -04:00
|
|
|
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
|
2021-12-01 16:34:40 +00:00
|
|
|
};
|
|
|
|
let param_env = tcx.param_env(defining_use_anchor);
|
2020-06-28 16:46:02 +01:00
|
|
|
|
2024-11-26 16:01:08 +01:00
|
|
|
// FIXME(#132279): Once `PostBorrowckAnalysis` is supported in the old solver, this branch should be removed.
|
|
|
|
let infcx = tcx.infer_ctxt().build(if tcx.next_trait_solver_globally() {
|
|
|
|
TypingMode::post_borrowck_analysis(tcx, defining_use_anchor)
|
|
|
|
} else {
|
|
|
|
TypingMode::analysis_in_body(tcx, defining_use_anchor)
|
|
|
|
});
|
2024-06-01 14:51:31 -04:00
|
|
|
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
2022-12-22 14:36:09 +03:00
|
|
|
|
2024-11-08 03:46:23 +00:00
|
|
|
let args = match origin {
|
2024-10-02 22:21:37 -04:00
|
|
|
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
|
|
|
| hir::OpaqueTyOrigin::AsyncFn { parent, .. }
|
2024-03-06 17:52:53 +00:00
|
|
|
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
|
|
|
|
tcx, parent,
|
|
|
|
)
|
|
|
|
.extend_to(tcx, def_id.to_def_id(), |param, _| {
|
2024-03-06 18:48:13 +00:00
|
|
|
tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
|
2024-03-06 17:52:53 +00:00
|
|
|
}),
|
2023-08-07 23:54:04 +00:00
|
|
|
};
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
2022-09-19 22:03:59 -05:00
|
|
|
|
2023-10-19 21:46:28 +00:00
|
|
|
// `ReErased` regions appear in the "parent_args" of closures/coroutines.
|
2022-10-13 13:49:38 +03:00
|
|
|
// We're ignoring them here and replacing them with fresh region variables.
|
2023-07-11 22:35:29 +01:00
|
|
|
// See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.
|
2022-10-13 13:49:38 +03:00
|
|
|
//
|
|
|
|
// FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
|
|
|
|
// here rather than using ReErased.
|
2023-07-11 22:35:29 +01:00
|
|
|
let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args);
|
2024-11-27 18:37:39 +01:00
|
|
|
let hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.kind() {
|
2022-10-13 13:49:38 +03:00
|
|
|
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
|
|
|
|
_ => re,
|
|
|
|
});
|
|
|
|
|
2024-11-08 04:27:20 +00:00
|
|
|
// HACK: We eagerly instantiate some bounds to report better errors for them...
|
|
|
|
// This isn't necessary for correctness, since we register these bounds when
|
|
|
|
// equating the opaque below, but we should clean this up in the new solver.
|
|
|
|
for (predicate, pred_span) in
|
|
|
|
tcx.explicit_item_bounds(def_id).iter_instantiated_copied(tcx, args)
|
|
|
|
{
|
|
|
|
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
|
|
|
tcx,
|
|
|
|
ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty },
|
|
|
|
lt_op: |lt| lt,
|
|
|
|
ct_op: |ct| ct,
|
|
|
|
});
|
|
|
|
|
|
|
|
ocx.register_obligation(Obligation::new(
|
|
|
|
tcx,
|
|
|
|
ObligationCause::new(
|
|
|
|
span,
|
|
|
|
def_id,
|
|
|
|
ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id),
|
|
|
|
),
|
|
|
|
param_env,
|
|
|
|
predicate,
|
|
|
|
));
|
|
|
|
}
|
2022-09-19 22:03:59 -05:00
|
|
|
|
2024-11-08 04:27:20 +00:00
|
|
|
let misc_cause = ObligationCause::misc(span, def_id);
|
2024-11-08 03:46:23 +00:00
|
|
|
// FIXME: We should just register the item bounds here, rather than equating.
|
2024-11-19 20:29:01 +00:00
|
|
|
// FIXME(const_trait_impl): When we do that, please make sure to also register
|
|
|
|
// the `~const` bounds.
|
2022-11-15 14:05:30 +01:00
|
|
|
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
|
|
|
|
Ok(()) => {}
|
2022-07-02 16:37:49 +03:00
|
|
|
Err(ty_err) => {
|
2024-03-13 13:44:00 -04:00
|
|
|
// Some types may be left "stranded" if they can't be reached
|
2024-02-11 09:22:52 +01:00
|
|
|
// from a lowered rustc_middle bound but they're mentioned in the HIR.
|
|
|
|
// This will happen, e.g., when a nested opaque is inside of a non-
|
2024-03-13 13:44:00 -04:00
|
|
|
// existent associated type, like `impl Trait<Missing = impl Trait>`.
|
|
|
|
// See <tests/ui/impl-trait/stranded-opaque.rs>.
|
2023-01-06 00:53:31 +00:00
|
|
|
let ty_err = ty_err.to_string(tcx);
|
2024-03-13 13:44:00 -04:00
|
|
|
let guar = tcx.dcx().span_delayed_bug(
|
2022-07-02 16:37:49 +03:00
|
|
|
span,
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
|
2024-02-17 01:23:40 +11:00
|
|
|
);
|
2024-03-13 13:44:00 -04:00
|
|
|
return Err(guar);
|
2022-07-02 16:37:49 +03:00
|
|
|
}
|
2022-02-11 07:18:06 +00:00
|
|
|
}
|
2020-06-28 16:46:02 +01:00
|
|
|
|
2022-07-02 16:37:49 +03:00
|
|
|
// Additionally require the hidden type to be well-formed with only the generics of the opaque type.
|
|
|
|
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
|
|
|
// hidden type is well formed even without those bounds.
|
2023-06-15 16:59:01 +00:00
|
|
|
let predicate =
|
2023-06-16 05:59:42 +00:00
|
|
|
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));
|
2023-07-20 09:36:02 +00:00
|
|
|
ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));
|
2022-09-19 22:03:59 -05:00
|
|
|
|
2022-07-02 16:37:49 +03:00
|
|
|
// Check that all obligations are satisfied by the implementation's
|
|
|
|
// version.
|
|
|
|
let errors = ocx.select_all_or_error();
|
|
|
|
if !errors.is_empty() {
|
2023-08-14 13:09:53 +00:00
|
|
|
let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
|
2023-06-27 23:13:39 +02:00
|
|
|
return Err(guar);
|
2021-12-01 16:34:40 +00:00
|
|
|
}
|
2024-02-27 17:30:24 +01:00
|
|
|
|
|
|
|
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;
|
2025-01-25 03:03:39 +00:00
|
|
|
ocx.resolve_regions_and_report_errors(defining_use_anchor, param_env, wf_tys)?;
|
2024-02-27 15:00:22 +01:00
|
|
|
|
2024-11-26 16:01:08 +01:00
|
|
|
if infcx.next_trait_solver() {
|
|
|
|
Ok(())
|
|
|
|
} else if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } =
|
|
|
|
origin
|
|
|
|
{
|
2024-02-27 15:00:22 +01:00
|
|
|
// HACK: this should also fall through to the hidden type check below, but the original
|
|
|
|
// implementation had a bug where equivalent lifetimes are not identical. This caused us
|
|
|
|
// to reject existing stable code that is otherwise completely fine. The real fix is to
|
|
|
|
// compare the hidden types via our type equivalence/relation infra instead of doing an
|
|
|
|
// identity check.
|
|
|
|
let _ = infcx.take_opaque_types();
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
|
|
|
for (mut key, mut ty) in infcx.take_opaque_types() {
|
2025-01-13 14:14:57 +01:00
|
|
|
ty.ty = infcx.resolve_vars_if_possible(ty.ty);
|
2024-02-27 15:00:22 +01:00
|
|
|
key = infcx.resolve_vars_if_possible(key);
|
2025-01-13 14:14:57 +01:00
|
|
|
sanity_check_found_hidden_type(tcx, key, ty)?;
|
2022-07-02 16:37:49 +03:00
|
|
|
}
|
2024-02-27 15:00:22 +01:00
|
|
|
Ok(())
|
2022-09-19 22:03:59 -05:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2024-11-08 04:27:20 +00:00
|
|
|
fn best_definition_site_of_opaque<'tcx>(
|
2024-11-08 03:46:23 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
opaque_def_id: LocalDefId,
|
|
|
|
origin: hir::OpaqueTyOrigin<LocalDefId>,
|
2024-11-08 04:27:20 +00:00
|
|
|
) -> Option<(Span, LocalDefId)> {
|
2024-11-08 03:46:23 +00:00
|
|
|
struct TaitConstraintLocator<'tcx> {
|
|
|
|
opaque_def_id: LocalDefId,
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
}
|
|
|
|
impl<'tcx> TaitConstraintLocator<'tcx> {
|
2024-11-08 04:27:20 +00:00
|
|
|
fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> {
|
2024-11-08 03:46:23 +00:00
|
|
|
if !self.tcx.has_typeck_results(item_def_id) {
|
|
|
|
return ControlFlow::Continue(());
|
|
|
|
}
|
|
|
|
|
2024-07-26 10:04:02 +00:00
|
|
|
let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
|
|
|
|
// Don't try to check items that cannot possibly constrain the type.
|
|
|
|
if !opaque_types_defined_by.contains(&self.opaque_def_id) {
|
|
|
|
return ControlFlow::Continue(());
|
|
|
|
}
|
|
|
|
|
2024-11-08 03:46:23 +00:00
|
|
|
if let Some(hidden_ty) =
|
|
|
|
self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
|
|
|
|
{
|
2024-11-08 04:27:20 +00:00
|
|
|
ControlFlow::Break((hidden_ty.span, item_def_id))
|
2024-11-08 03:46:23 +00:00
|
|
|
} else {
|
|
|
|
ControlFlow::Continue(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
|
|
|
|
type NestedFilter = nested_filter::All;
|
2024-11-08 04:27:20 +00:00
|
|
|
type Result = ControlFlow<(Span, LocalDefId)>;
|
2025-02-03 14:42:01 +11:00
|
|
|
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
|
|
|
self.tcx
|
2024-11-08 03:46:23 +00:00
|
|
|
}
|
|
|
|
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
|
|
|
if let hir::ExprKind::Closure(closure) = ex.kind {
|
|
|
|
self.check(closure.def_id)?;
|
|
|
|
}
|
|
|
|
intravisit::walk_expr(self, ex)
|
|
|
|
}
|
|
|
|
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {
|
|
|
|
self.check(it.owner_id.def_id)?;
|
|
|
|
intravisit::walk_item(self, it)
|
|
|
|
}
|
|
|
|
fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result {
|
|
|
|
self.check(it.owner_id.def_id)?;
|
|
|
|
intravisit::walk_impl_item(self, it)
|
|
|
|
}
|
|
|
|
fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result {
|
|
|
|
self.check(it.owner_id.def_id)?;
|
|
|
|
intravisit::walk_trait_item(self, it)
|
|
|
|
}
|
|
|
|
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result {
|
|
|
|
intravisit::walk_foreign_item(self, it)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut locator = TaitConstraintLocator { tcx, opaque_def_id };
|
|
|
|
match origin {
|
|
|
|
hir::OpaqueTyOrigin::FnReturn { parent, .. }
|
|
|
|
| hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(),
|
|
|
|
hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => {
|
|
|
|
let impl_def_id = tcx.local_parent(parent);
|
|
|
|
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
|
|
|
|
match assoc.kind {
|
|
|
|
ty::AssocKind::Const | ty::AssocKind::Fn => {
|
|
|
|
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
|
|
|
|
{
|
|
|
|
return Some(span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::AssocKind::Type => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
|
2024-07-26 10:04:02 +00:00
|
|
|
tcx.hir_walk_toplevel_module(&mut locator).break_value()
|
2024-11-08 03:46:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-20 09:36:02 +00:00
|
|
|
fn sanity_check_found_hidden_type<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
key: ty::OpaqueTypeKey<'tcx>,
|
|
|
|
mut ty: ty::OpaqueHiddenType<'tcx>,
|
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
|
|
|
if ty.ty.is_ty_var() {
|
|
|
|
// Nothing was actually constrained.
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
if let ty::Alias(ty::Opaque, alias) = ty.ty.kind() {
|
|
|
|
if alias.def_id == key.def_id.to_def_id() && alias.args == key.args {
|
|
|
|
// Nothing was actually constrained, this is an opaque usage that was
|
|
|
|
// only discovered to be opaque after inference vars resolved.
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
2023-08-07 08:33:25 +00:00
|
|
|
let strip_vars = |ty: Ty<'tcx>| {
|
|
|
|
ty.fold_with(&mut BottomUpFolder {
|
|
|
|
tcx,
|
|
|
|
ty_op: |t| t,
|
|
|
|
ct_op: |c| c,
|
|
|
|
lt_op: |l| match l.kind() {
|
|
|
|
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
|
|
|
|
_ => l,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
};
|
2023-07-20 09:36:02 +00:00
|
|
|
// Closures frequently end up containing erased lifetimes in their final representation.
|
|
|
|
// These correspond to lifetime variables that never got resolved, so we patch this up here.
|
2023-08-07 08:33:25 +00:00
|
|
|
ty.ty = strip_vars(ty.ty);
|
2023-07-21 14:28:22 +00:00
|
|
|
// Get the hidden type.
|
2023-08-07 08:33:25 +00:00
|
|
|
let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
|
|
|
|
let hidden_ty = strip_vars(hidden_ty);
|
2023-07-21 14:28:22 +00:00
|
|
|
|
2023-07-20 09:36:02 +00:00
|
|
|
// If the hidden types differ, emit a type mismatch diagnostic.
|
|
|
|
if hidden_ty == ty.ty {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
let span = tcx.def_span(key.def_id);
|
|
|
|
let other = ty::OpaqueHiddenType { ty: hidden_ty, span };
|
2025-01-11 19:22:02 +00:00
|
|
|
Err(ty.build_mismatch_error(&other, tcx)?.emit())
|
2023-07-20 09:36:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 20:36:18 -04:00
|
|
|
/// Check that the opaque's precise captures list is valid (if present).
|
|
|
|
/// We check this for regular `impl Trait`s and also RPITITs, even though the latter
|
|
|
|
/// are technically GATs.
|
|
|
|
///
|
|
|
|
/// This function is responsible for:
|
|
|
|
/// 1. Checking that all type/const params are mention in the captures list.
|
|
|
|
/// 2. Checking that all lifetimes that are implicitly captured are mentioned.
|
|
|
|
/// 3. Asserting that all parameters mentioned in the captures list are invariant.
|
2024-04-04 12:54:56 -04:00
|
|
|
fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
|
2024-08-09 20:43:30 -07:00
|
|
|
let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
|
2024-06-05 16:18:52 -04:00
|
|
|
let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
|
|
|
|
hir::GenericBound::Use(bounds, ..) => Some(bounds),
|
|
|
|
_ => None,
|
|
|
|
}) else {
|
2024-04-04 12:54:56 -04:00
|
|
|
// No precise capturing args; nothing to validate
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut expected_captures = UnordSet::default();
|
2024-04-17 21:30:41 -04:00
|
|
|
let mut shadowed_captures = UnordSet::default();
|
2024-04-04 15:06:30 -04:00
|
|
|
let mut seen_params = UnordMap::default();
|
|
|
|
let mut prev_non_lifetime_param = None;
|
2024-04-04 12:54:56 -04:00
|
|
|
for arg in precise_capturing_args {
|
2024-04-04 15:06:30 -04:00
|
|
|
let (hir_id, ident) = match *arg {
|
|
|
|
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
|
|
|
|
hir_id,
|
|
|
|
ident,
|
|
|
|
..
|
|
|
|
}) => {
|
|
|
|
if prev_non_lifetime_param.is_none() {
|
|
|
|
prev_non_lifetime_param = Some(ident);
|
2024-04-04 12:54:56 -04:00
|
|
|
}
|
2024-04-04 15:06:30 -04:00
|
|
|
(hir_id, ident)
|
|
|
|
}
|
|
|
|
hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {
|
|
|
|
if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {
|
|
|
|
tcx.dcx().emit_err(errors::LifetimesMustBeFirst {
|
|
|
|
lifetime_span: ident.span,
|
|
|
|
name: ident.name,
|
|
|
|
other_span: prev_non_lifetime_param.span,
|
|
|
|
});
|
2024-04-04 12:54:56 -04:00
|
|
|
}
|
2024-04-04 15:06:30 -04:00
|
|
|
(hir_id, ident)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let ident = ident.normalize_to_macros_2_0();
|
|
|
|
if let Some(span) = seen_params.insert(ident, ident.span) {
|
|
|
|
tcx.dcx().emit_err(errors::DuplicatePreciseCapture {
|
|
|
|
name: ident.name,
|
|
|
|
first_span: span,
|
|
|
|
second_span: ident.span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
match tcx.named_bound_var(hir_id) {
|
|
|
|
Some(ResolvedArg::EarlyBound(def_id)) => {
|
2024-08-22 01:17:01 +00:00
|
|
|
expected_captures.insert(def_id.to_def_id());
|
2024-04-17 21:30:41 -04:00
|
|
|
|
|
|
|
// Make sure we allow capturing these lifetimes through `Self` and
|
|
|
|
// `T::Assoc` projection syntax, too. These will occur when we only
|
|
|
|
// see lifetimes are captured after hir-lowering -- this aligns with
|
|
|
|
// the cases that were stabilized with the `impl_trait_projection`
|
|
|
|
// feature -- see <https://github.com/rust-lang/rust/pull/115659>.
|
|
|
|
if let DefKind::LifetimeParam = tcx.def_kind(def_id)
|
2024-05-23 23:53:56 +01:00
|
|
|
&& let Some(def_id) = tcx
|
2024-08-22 01:17:01 +00:00
|
|
|
.map_opaque_lifetime_to_parent_lifetime(def_id)
|
2024-05-23 23:53:56 +01:00
|
|
|
.opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))
|
2024-04-17 21:30:41 -04:00
|
|
|
{
|
|
|
|
shadowed_captures.insert(def_id);
|
|
|
|
}
|
2024-04-04 15:06:30 -04:00
|
|
|
}
|
|
|
|
_ => {
|
2025-04-02 07:04:24 +11:00
|
|
|
tcx.dcx()
|
|
|
|
.span_delayed_bug(tcx.hir_span(hir_id), "parameter should have been resolved");
|
2024-04-04 15:06:30 -04:00
|
|
|
}
|
2024-04-04 12:54:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let variances = tcx.variances_of(opaque_def_id);
|
|
|
|
let mut def_id = Some(opaque_def_id.to_def_id());
|
|
|
|
while let Some(generics) = def_id {
|
|
|
|
let generics = tcx.generics_of(generics);
|
|
|
|
def_id = generics.parent;
|
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
for param in &generics.own_params {
|
2024-04-04 12:54:56 -04:00
|
|
|
if expected_captures.contains(¶m.def_id) {
|
|
|
|
assert_eq!(
|
|
|
|
variances[param.index as usize],
|
|
|
|
ty::Invariant,
|
|
|
|
"precise captured param should be invariant"
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
2024-04-17 21:30:41 -04:00
|
|
|
// If a param is shadowed by a early-bound (duplicated) lifetime, then
|
|
|
|
// it may or may not be captured as invariant, depending on if it shows
|
|
|
|
// up through `Self` or `T::Assoc` syntax.
|
|
|
|
if shadowed_captures.contains(¶m.def_id) {
|
|
|
|
continue;
|
|
|
|
}
|
2024-04-04 12:54:56 -04:00
|
|
|
|
|
|
|
match param.kind {
|
|
|
|
ty::GenericParamDefKind::Lifetime => {
|
2024-04-19 15:18:00 -04:00
|
|
|
let use_span = tcx.def_span(param.def_id);
|
|
|
|
let opaque_span = tcx.def_span(opaque_def_id);
|
2024-04-04 12:54:56 -04:00
|
|
|
// Check if the lifetime param was captured but isn't named in the precise captures list.
|
|
|
|
if variances[param.index as usize] == ty::Invariant {
|
2024-04-19 15:18:00 -04:00
|
|
|
if let DefKind::OpaqueTy = tcx.def_kind(tcx.parent(param.def_id))
|
2024-05-23 23:53:56 +01:00
|
|
|
&& let Some(def_id) = tcx
|
2024-04-04 12:54:56 -04:00
|
|
|
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
|
2024-05-23 23:53:56 +01:00
|
|
|
.opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))
|
2024-04-17 21:30:41 -04:00
|
|
|
{
|
2024-04-19 15:18:00 -04:00
|
|
|
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
|
|
|
|
opaque_span,
|
|
|
|
use_span,
|
|
|
|
param_span: tcx.def_span(def_id),
|
|
|
|
});
|
2024-04-17 21:30:41 -04:00
|
|
|
} else {
|
2024-09-29 13:49:32 -04:00
|
|
|
if tcx.def_kind(tcx.parent(param.def_id)) == DefKind::Trait {
|
|
|
|
tcx.dcx().emit_err(errors::LifetimeImplicitlyCaptured {
|
|
|
|
opaque_span,
|
|
|
|
param_span: tcx.def_span(param.def_id),
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// If the `use_span` is actually just the param itself, then we must
|
|
|
|
// have not duplicated the lifetime but captured the original.
|
|
|
|
// The "effective" `use_span` will be the span of the opaque itself,
|
|
|
|
// and the param span will be the def span of the param.
|
|
|
|
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
|
|
|
|
opaque_span,
|
|
|
|
use_span: opaque_span,
|
|
|
|
param_span: use_span,
|
|
|
|
});
|
|
|
|
}
|
2024-04-19 15:18:00 -04:00
|
|
|
}
|
2024-04-04 12:54:56 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::GenericParamDefKind::Type { .. } => {
|
2024-04-20 11:39:43 -04:00
|
|
|
if matches!(tcx.def_kind(param.def_id), DefKind::Trait | DefKind::TraitAlias) {
|
|
|
|
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
|
|
|
tcx.dcx().emit_err(errors::SelfTyNotCaptured {
|
|
|
|
trait_span: tcx.def_span(param.def_id),
|
|
|
|
opaque_span: tcx.def_span(opaque_def_id),
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
|
|
|
tcx.dcx().emit_err(errors::ParamNotCaptured {
|
|
|
|
param_span: tcx.def_span(param.def_id),
|
|
|
|
opaque_span: tcx.def_span(opaque_def_id),
|
|
|
|
kind: "type",
|
|
|
|
});
|
|
|
|
}
|
2024-04-04 12:54:56 -04:00
|
|
|
}
|
|
|
|
ty::GenericParamDefKind::Const { .. } => {
|
|
|
|
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
|
|
|
tcx.dcx().emit_err(errors::ParamNotCaptured {
|
|
|
|
param_span: tcx.def_span(param.def_id),
|
|
|
|
opaque_span: tcx.def_span(opaque_def_id),
|
|
|
|
kind: "const",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-23 18:15:50 -08:00
|
|
|
fn is_enum_of_nonnullable_ptr<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
adt_def: AdtDef<'tcx>,
|
2023-07-11 22:35:29 +01:00
|
|
|
args: GenericArgsRef<'tcx>,
|
2022-11-23 18:15:50 -08:00
|
|
|
) -> bool {
|
|
|
|
if adt_def.repr().inhibit_enum_layout_opt() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let [var_one, var_two] = &adt_def.variants().raw[..] else {
|
|
|
|
return false;
|
|
|
|
};
|
2023-03-28 23:32:25 -07:00
|
|
|
let (([], [field]) | ([field], [])) = (&var_one.fields.raw[..], &var_two.fields.raw[..]) else {
|
2022-11-23 18:15:50 -08:00
|
|
|
return false;
|
|
|
|
};
|
2023-07-11 22:35:29 +01:00
|
|
|
matches!(field.ty(tcx, args).kind(), ty::FnPtr(..) | ty::Ref(..))
|
2022-11-23 18:15:50 -08:00
|
|
|
}
|
|
|
|
|
2022-12-20 22:10:40 +01:00
|
|
|
fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
Move linkage type check to HIR analysis and fix semantics issues.
This ensures that the error is printed even for unused variables,
as well as unifying the handling between the LLVM and GCC backends.
This also fixes unusual behavior around exported Rust-defined variables
with linkage attributes. With the previous behavior, it appears to be
impossible to define such a variable such that it can actually be imported
and used by another crate. This is because on the importing side, the
variable is required to be a pointer, but on the exporting side, the
type checker rejects static variables of pointer type because they do
not implement `Sync`. Even if it were possible to import such a type, it
appears that code generation on the importing side would add an unexpected
additional level of pointer indirection, which would break type safety.
This highlighted that the semantics of linkage on Rust-defined variables
is different to linkage on foreign items. As such, we now model the
difference with two different codegen attributes: linkage for Rust-defined
variables, and import_linkage for foreign items.
This change gives semantics to the test
src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs which was
previously expected to fail to compile. Therefore, convert it into a
test that is expected to successfully compile.
The update to the GCC backend is speculative and untested.
2022-11-23 18:13:30 -08:00
|
|
|
if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
|
2023-07-11 22:35:29 +01:00
|
|
|
if match tcx.type_of(def_id).instantiate_identity().kind() {
|
2024-03-21 17:11:06 -04:00
|
|
|
ty::RawPtr(_, _) => false,
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
|
Move linkage type check to HIR analysis and fix semantics issues.
This ensures that the error is printed even for unused variables,
as well as unifying the handling between the LLVM and GCC backends.
This also fixes unusual behavior around exported Rust-defined variables
with linkage attributes. With the previous behavior, it appears to be
impossible to define such a variable such that it can actually be imported
and used by another crate. This is because on the importing side, the
variable is required to be a pointer, but on the exporting side, the
type checker rejects static variables of pointer type because they do
not implement `Sync`. Even if it were possible to import such a type, it
appears that code generation on the importing side would add an unexpected
additional level of pointer indirection, which would break type safety.
This highlighted that the semantics of linkage on Rust-defined variables
is different to linkage on foreign items. As such, we now model the
difference with two different codegen attributes: linkage for Rust-defined
variables, and import_linkage for foreign items.
This change gives semantics to the test
src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs which was
previously expected to fail to compile. Therefore, convert it into a
test that is expected to successfully compile.
The update to the GCC backend is speculative and untested.
2022-11-23 18:13:30 -08:00
|
|
|
_ => true,
|
|
|
|
} {
|
2024-04-04 12:54:56 -04:00
|
|
|
tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) });
|
Move linkage type check to HIR analysis and fix semantics issues.
This ensures that the error is printed even for unused variables,
as well as unifying the handling between the LLVM and GCC backends.
This also fixes unusual behavior around exported Rust-defined variables
with linkage attributes. With the previous behavior, it appears to be
impossible to define such a variable such that it can actually be imported
and used by another crate. This is because on the importing side, the
variable is required to be a pointer, but on the exporting side, the
type checker rejects static variables of pointer type because they do
not implement `Sync`. Even if it were possible to import such a type, it
appears that code generation on the importing side would add an unexpected
additional level of pointer indirection, which would break type safety.
This highlighted that the semantics of linkage on Rust-defined variables
is different to linkage on foreign items. As such, we now model the
difference with two different codegen attributes: linkage for Rust-defined
variables, and import_linkage for foreign items.
This change gives semantics to the test
src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs which was
previously expected to fail to compile. Therefore, convert it into a
test that is expected to successfully compile.
The update to the GCC backend is speculative and untested.
2022-11-23 18:13:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-26 11:36:49 +00:00
|
|
|
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2023-10-26 10:15:26 +00:00
|
|
|
match tcx.def_kind(def_id) {
|
2024-02-23 23:12:20 +00:00
|
|
|
DefKind::Static { .. } => {
|
2023-10-26 10:15:26 +00:00
|
|
|
check_static_inhabited(tcx, def_id);
|
|
|
|
check_static_linkage(tcx, def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2025-02-21 19:22:08 +00:00
|
|
|
DefKind::Const => {}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Enum => {
|
2023-10-26 10:15:26 +00:00
|
|
|
check_enum(tcx, def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2024-01-31 14:28:40 +00:00
|
|
|
DefKind::Fn => {
|
2024-02-19 17:35:12 +00:00
|
|
|
if let Some(i) = tcx.intrinsic(def_id) {
|
2024-01-31 14:28:40 +00:00
|
|
|
intrinsic::check_intrinsic_type(
|
|
|
|
tcx,
|
|
|
|
def_id,
|
|
|
|
tcx.def_ident_span(def_id).unwrap(),
|
2024-02-19 17:35:12 +00:00
|
|
|
i.name,
|
2024-11-02 19:32:56 -07:00
|
|
|
ExternAbi::Rust,
|
2024-01-31 14:28:40 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2023-02-12 18:26:47 +00:00
|
|
|
DefKind::Impl { of_trait } => {
|
2024-02-10 22:27:03 +00:00
|
|
|
if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
|
2024-04-09 10:23:58 +00:00
|
|
|
if tcx
|
2025-01-30 16:20:09 +11:00
|
|
|
.ensure_ok()
|
2024-04-09 10:23:58 +00:00
|
|
|
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id)
|
|
|
|
.is_ok()
|
|
|
|
{
|
|
|
|
check_impl_items_against_trait(tcx, def_id, impl_trait_header);
|
|
|
|
check_on_unimplemented(tcx, def_id);
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Trait => {
|
2023-10-26 10:15:26 +00:00
|
|
|
let assoc_items = tcx.associated_items(def_id);
|
|
|
|
check_on_unimplemented(tcx, def_id);
|
2023-02-12 18:49:54 +00:00
|
|
|
|
2023-02-06 08:57:34 +00:00
|
|
|
for &assoc_item in assoc_items.in_definition_order() {
|
2023-02-12 18:49:54 +00:00
|
|
|
match assoc_item.kind {
|
|
|
|
ty::AssocKind::Fn => {
|
|
|
|
let abi = tcx.fn_sig(assoc_item.def_id).skip_binder().abi();
|
2023-12-12 12:28:54 +00:00
|
|
|
forbid_intrinsic_abi(tcx, assoc_item.ident(tcx).span, abi);
|
2020-06-27 21:36:35 +01:00
|
|
|
}
|
2023-02-12 18:49:54 +00:00
|
|
|
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
2023-10-26 10:15:26 +00:00
|
|
|
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
|
2022-01-23 12:34:26 -06:00
|
|
|
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
2020-06-27 21:36:35 +01:00
|
|
|
tcx,
|
|
|
|
assoc_item,
|
|
|
|
assoc_item,
|
2024-06-21 13:33:08 -04:00
|
|
|
ty::TraitRef::new_from_args(tcx, def_id.to_def_id(), trait_args),
|
2020-06-27 21:36:35 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Struct => {
|
2023-10-26 10:15:26 +00:00
|
|
|
check_struct(tcx, def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Union => {
|
2023-10-26 10:15:26 +00:00
|
|
|
check_union(tcx, def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::OpaqueTy => {
|
2024-04-04 12:54:56 -04:00
|
|
|
check_opaque_precise_captures(tcx, def_id);
|
|
|
|
|
2024-10-02 23:16:31 -04:00
|
|
|
let origin = tcx.local_opaque_ty_origin(def_id);
|
2024-10-02 22:21:37 -04:00
|
|
|
if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
|
|
|
|
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin
|
2023-12-01 05:28:34 -08:00
|
|
|
&& let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
|
2023-03-20 17:05:46 +00:00
|
|
|
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
|
|
|
|
{
|
|
|
|
// Skip opaques from RPIT in traits with no default body.
|
|
|
|
} else {
|
2023-10-26 10:15:26 +00:00
|
|
|
check_opaque(tcx, def_id);
|
2023-03-20 17:05:46 +00:00
|
|
|
}
|
2022-09-30 19:16:13 +00:00
|
|
|
}
|
2023-09-26 02:15:32 +00:00
|
|
|
DefKind::TyAlias => {
|
2024-02-01 15:58:07 +01:00
|
|
|
check_type_alias_type_params_are_used(tcx, def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::ForeignMod => {
|
2025-02-21 18:33:05 +11:00
|
|
|
let it = tcx.hir_expect_item(def_id);
|
2022-04-29 13:09:03 -04:00
|
|
|
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
|
|
|
|
return;
|
|
|
|
};
|
2024-09-03 18:48:15 +02:00
|
|
|
check_abi(tcx, it.span, abi);
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2023-01-30 11:03:32 +00:00
|
|
|
match abi {
|
2024-11-02 19:32:56 -07:00
|
|
|
ExternAbi::RustIntrinsic => {
|
2023-01-30 11:03:32 +00:00
|
|
|
for item in items {
|
2024-01-31 14:28:40 +00:00
|
|
|
intrinsic::check_intrinsic_type(
|
|
|
|
tcx,
|
|
|
|
item.id.owner_id.def_id,
|
|
|
|
item.span,
|
|
|
|
item.ident.name,
|
|
|
|
abi,
|
|
|
|
);
|
2023-01-30 11:03:32 +00:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2023-01-30 11:03:32 +00:00
|
|
|
|
|
|
|
_ => {
|
|
|
|
for item in items {
|
|
|
|
let def_id = item.id.owner_id.def_id;
|
|
|
|
let generics = tcx.generics_of(def_id);
|
|
|
|
let own_counts = generics.own_counts();
|
2024-05-09 20:56:44 -04:00
|
|
|
if generics.own_params.len() - own_counts.lifetimes != 0 {
|
2023-01-30 11:03:32 +00:00
|
|
|
let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts)
|
|
|
|
{
|
|
|
|
(_, 0) => ("type", "types", Some("u32")),
|
|
|
|
// We don't specify an example value, because we can't generate
|
|
|
|
// a valid value for any type.
|
|
|
|
(0, _) => ("const", "consts", None),
|
|
|
|
_ => ("type or const", "types or consts", None),
|
|
|
|
};
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2023-01-30 11:03:32 +00:00
|
|
|
item.span,
|
|
|
|
E0044,
|
|
|
|
"foreign items may not have {kinds} parameters",
|
|
|
|
)
|
2024-01-09 09:08:49 +11:00
|
|
|
.with_span_label(item.span, format!("can't have {kinds} parameters"))
|
|
|
|
.with_help(
|
2023-01-30 11:03:32 +00:00
|
|
|
// FIXME: once we start storing spans for type arguments, turn this
|
|
|
|
// into a suggestion.
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
format!(
|
2023-01-30 11:03:32 +00:00
|
|
|
"replace the {} parameters with concrete {}{}",
|
|
|
|
kinds,
|
|
|
|
kinds_pl,
|
2023-07-25 23:17:39 +02:00
|
|
|
egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),
|
2023-01-30 11:03:32 +00:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.emit();
|
2020-10-24 16:13:39 +02:00
|
|
|
}
|
2023-01-30 11:03:32 +00:00
|
|
|
|
2025-02-03 10:45:49 +11:00
|
|
|
let item = tcx.hir_foreign_item(item.id);
|
2023-01-30 11:03:32 +00:00
|
|
|
match &item.kind {
|
2024-08-07 13:01:34 -04:00
|
|
|
hir::ForeignItemKind::Fn(sig, _, _) => {
|
|
|
|
require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
|
2023-01-30 11:03:32 +00:00
|
|
|
}
|
|
|
|
hir::ForeignItemKind::Static(..) => {
|
|
|
|
check_static_inhabited(tcx, def_id);
|
|
|
|
check_static_linkage(tcx, def_id);
|
|
|
|
}
|
|
|
|
_ => {}
|
2020-10-24 16:13:39 +02:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
_ => {}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-26 10:15:26 +00:00
|
|
|
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2020-09-19 13:51:59 -07:00
|
|
|
// an error would be reported if this fails.
|
2023-10-26 10:15:26 +00:00
|
|
|
let _ = OnUnimplementedDirective::of_item(tcx, def_id.to_def_id());
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn check_specialization_validity<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
trait_def: &ty::TraitDef,
|
2023-02-06 08:57:34 +00:00
|
|
|
trait_item: ty::AssocItem,
|
2020-09-19 13:51:59 -07:00
|
|
|
impl_id: DefId,
|
2023-02-12 18:49:54 +00:00
|
|
|
impl_item: DefId,
|
2020-09-19 13:51:59 -07:00
|
|
|
) {
|
2022-02-19 00:44:45 +01:00
|
|
|
let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) else { return };
|
2021-01-22 18:15:55 +01:00
|
|
|
let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {
|
|
|
|
if parent.is_from_trait() {
|
|
|
|
None
|
|
|
|
} else {
|
2021-11-18 21:35:42 +00:00
|
|
|
Some((parent, parent.item(tcx, trait_item.def_id)))
|
2021-01-22 18:15:55 +01:00
|
|
|
}
|
|
|
|
});
|
2020-09-19 13:51:59 -07:00
|
|
|
|
|
|
|
let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
|
|
|
|
match parent_item {
|
|
|
|
// Parent impl exists, and contains the parent item we're trying to specialize, but
|
|
|
|
// doesn't mark it `default`.
|
|
|
|
Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
|
|
|
|
Some(Err(parent_impl.def_id()))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parent impl contains item and makes it specializable.
|
|
|
|
Some(_) => Some(Ok(())),
|
|
|
|
|
|
|
|
// Parent impl doesn't mention the item. This means it's inherited from the
|
|
|
|
// grandparent. In that case, if parent is a `default impl`, inherited items use the
|
|
|
|
// "defaultness" from the grandparent, else they are final.
|
|
|
|
None => {
|
2023-06-01 06:14:06 +00:00
|
|
|
if tcx.defaultness(parent_impl.def_id()).is_default() {
|
2020-09-19 13:51:59 -07:00
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Err(parent_impl.def_id()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the
|
|
|
|
// item. This is allowed, the item isn't actually getting specialized here.
|
|
|
|
let result = opt_result.unwrap_or(Ok(()));
|
|
|
|
|
|
|
|
if let Err(parent_impl) = result {
|
2024-10-30 23:52:10 +01:00
|
|
|
if !tcx.is_impl_trait_in_trait(impl_item) {
|
2023-07-07 15:24:10 -03:00
|
|
|
report_forbidden_specialization(tcx, impl_item, parent_impl);
|
|
|
|
} else {
|
2024-01-04 12:54:23 +11:00
|
|
|
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
|
2023-07-07 15:24:10 -03:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 21:35:42 +00:00
|
|
|
fn check_impl_items_against_trait<'tcx>(
|
2020-09-19 13:51:59 -07:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
impl_id: LocalDefId,
|
2024-02-10 22:27:03 +00:00
|
|
|
impl_trait_header: ty::ImplTraitHeader<'tcx>,
|
2020-09-19 13:51:59 -07:00
|
|
|
) {
|
2024-03-05 20:19:05 +01:00
|
|
|
let trait_ref = impl_trait_header.trait_ref.instantiate_identity();
|
2020-09-19 13:51:59 -07:00
|
|
|
// If the trait reference itself is erroneous (so the compilation is going
|
|
|
|
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
|
|
|
|
// isn't populated for such impls.
|
2024-03-05 20:19:05 +01:00
|
|
|
if trait_ref.references_error() {
|
2020-09-19 13:51:59 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-02-12 18:49:54 +00:00
|
|
|
let impl_item_refs = tcx.associated_item_def_ids(impl_id);
|
|
|
|
|
2020-09-19 13:51:59 -07:00
|
|
|
// Negative impls are not expected to have any items
|
2024-02-10 22:27:03 +00:00
|
|
|
match impl_trait_header.polarity {
|
2020-09-19 13:51:59 -07:00
|
|
|
ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
|
|
|
|
ty::ImplPolarity::Negative => {
|
|
|
|
if let [first_item_ref, ..] = impl_item_refs {
|
2023-02-12 18:49:54 +00:00
|
|
|
let first_item_span = tcx.def_span(first_item_ref);
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2020-09-19 13:51:59 -07:00
|
|
|
first_item_span,
|
|
|
|
E0749,
|
|
|
|
"negative impls cannot have any items"
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-05 20:19:05 +01:00
|
|
|
let trait_def = tcx.trait_def(trait_ref.def_id);
|
2021-01-22 18:15:55 +01:00
|
|
|
|
2025-01-14 11:02:29 +00:00
|
|
|
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
|
|
|
|
|
|
|
|
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
|
|
|
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
|
|
|
|
let param_env = tcx.param_env(impl_id);
|
|
|
|
|
|
|
|
let self_is_guaranteed_unsized = match tcx
|
|
|
|
.struct_tail_raw(
|
|
|
|
trait_ref.self_ty(),
|
|
|
|
|ty| {
|
|
|
|
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
|
|
|
|
Ty::new_error_with_message(
|
|
|
|
tcx,
|
|
|
|
tcx.def_span(impl_id),
|
|
|
|
"struct tail should be computable",
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|| (),
|
|
|
|
)
|
|
|
|
.kind()
|
|
|
|
{
|
|
|
|
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
2023-02-12 18:49:54 +00:00
|
|
|
for &impl_item in impl_item_refs {
|
|
|
|
let ty_impl_item = tcx.associated_item(impl_item);
|
2021-11-18 21:35:42 +00:00
|
|
|
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
|
|
|
|
tcx.associated_item(trait_item_id)
|
2021-01-22 18:15:55 +01:00
|
|
|
} else {
|
2021-11-18 21:35:42 +00:00
|
|
|
// Checked in `associated_item`.
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait");
|
2021-01-22 18:15:55 +01:00
|
|
|
continue;
|
|
|
|
};
|
2024-11-23 04:48:01 +00:00
|
|
|
|
2025-01-30 16:20:09 +11:00
|
|
|
let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local());
|
2024-11-30 16:44:58 +00:00
|
|
|
|
|
|
|
if res.is_ok() {
|
|
|
|
match ty_impl_item.kind {
|
|
|
|
ty::AssocKind::Fn => {
|
|
|
|
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
|
|
|
|
tcx,
|
|
|
|
ty_impl_item,
|
|
|
|
ty_trait_item,
|
|
|
|
tcx.impl_trait_ref(ty_impl_item.container_id(tcx))
|
|
|
|
.unwrap()
|
|
|
|
.instantiate_identity(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ty::AssocKind::Const => {}
|
|
|
|
ty::AssocKind::Type => {}
|
|
|
|
}
|
|
|
|
}
|
2021-11-18 21:35:42 +00:00
|
|
|
|
2025-01-14 11:02:29 +00:00
|
|
|
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
|
|
|
|
tcx.emit_node_span_lint(
|
|
|
|
rustc_lint_defs::builtin::DEAD_CODE,
|
|
|
|
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
|
|
|
|
tcx.def_span(ty_impl_item.def_id),
|
|
|
|
errors::UselessImplItem,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-18 21:35:42 +00:00
|
|
|
check_specialization_validity(
|
|
|
|
tcx,
|
|
|
|
trait_def,
|
2023-02-06 08:57:34 +00:00
|
|
|
ty_trait_item,
|
2021-11-18 21:35:42 +00:00
|
|
|
impl_id.to_def_id(),
|
|
|
|
impl_item,
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
|
2021-01-22 08:22:15 +01:00
|
|
|
// Check for missing items from trait
|
|
|
|
let mut missing_items = Vec::new();
|
2021-12-21 18:40:50 +03:00
|
|
|
|
2022-01-14 16:52:30 +03:00
|
|
|
let mut must_implement_one_of: Option<&[Ident]> =
|
|
|
|
trait_def.must_implement_one_of.as_deref();
|
2021-12-21 18:40:50 +03:00
|
|
|
|
2024-03-05 20:19:05 +01:00
|
|
|
for &trait_item_id in tcx.associated_item_def_ids(trait_ref.def_id) {
|
2023-02-28 02:03:26 +00:00
|
|
|
let leaf_def = ancestors.leaf_def(tcx, trait_item_id);
|
|
|
|
|
|
|
|
let is_implemented = leaf_def
|
|
|
|
.as_ref()
|
2023-05-24 14:19:22 +00:00
|
|
|
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2025-01-14 11:02:29 +00:00
|
|
|
if !is_implemented
|
|
|
|
&& tcx.defaultness(impl_id).is_final()
|
|
|
|
// unsized types don't need to implement methods that have `Self: Sized` bounds.
|
|
|
|
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
|
|
|
|
{
|
2021-11-18 21:35:42 +00:00
|
|
|
missing_items.push(tcx.associated_item(trait_item_id));
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2021-12-21 18:40:50 +03:00
|
|
|
|
2022-04-27 18:14:19 +04:00
|
|
|
// true if this item is specifically implemented in this impl
|
2023-05-24 14:19:22 +00:00
|
|
|
let is_implemented_here =
|
|
|
|
leaf_def.as_ref().is_some_and(|node_item| !node_item.defining_node.is_from_trait());
|
2022-04-27 18:14:19 +04:00
|
|
|
|
|
|
|
if !is_implemented_here {
|
2025-04-02 07:04:24 +11:00
|
|
|
let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));
|
2022-04-27 18:14:19 +04:00
|
|
|
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
|
2022-06-20 16:07:14 +04:00
|
|
|
EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
|
|
|
|
tcx,
|
|
|
|
full_impl_span,
|
|
|
|
trait_item_id,
|
|
|
|
feature,
|
|
|
|
reason,
|
|
|
|
issue,
|
|
|
|
),
|
2022-01-10 12:54:04 +03:00
|
|
|
|
2022-04-27 18:14:19 +04:00
|
|
|
// Unmarked default bodies are considered stable (at least for now).
|
|
|
|
EvalResult::Allow | EvalResult::Unmarked => {}
|
|
|
|
}
|
|
|
|
}
|
2022-01-10 12:54:04 +03:00
|
|
|
|
2022-04-27 18:14:19 +04:00
|
|
|
if let Some(required_items) = &must_implement_one_of {
|
2022-01-10 12:54:04 +03:00
|
|
|
if is_implemented_here {
|
|
|
|
let trait_item = tcx.associated_item(trait_item_id);
|
2022-01-12 21:15:51 -05:00
|
|
|
if required_items.contains(&trait_item.ident(tcx)) {
|
2022-01-10 12:54:04 +03:00
|
|
|
must_implement_one_of = None;
|
|
|
|
}
|
2021-12-21 18:40:50 +03:00
|
|
|
}
|
|
|
|
}
|
2023-02-28 02:03:26 +00:00
|
|
|
|
|
|
|
if let Some(leaf_def) = &leaf_def
|
|
|
|
&& !leaf_def.is_final()
|
|
|
|
&& let def_id = leaf_def.item.def_id
|
|
|
|
&& tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
|
|
|
{
|
|
|
|
let def_kind = tcx.def_kind(def_id);
|
|
|
|
let descr = tcx.def_kind_descr(def_kind, def_id);
|
|
|
|
let (msg, feature) = if tcx.asyncness(def_id).is_async() {
|
|
|
|
(
|
|
|
|
format!("async {descr} in trait cannot be specialized"),
|
2023-09-13 16:04:42 +00:00
|
|
|
"async functions in traits",
|
2023-02-28 02:03:26 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(
|
|
|
|
format!(
|
|
|
|
"{descr} with return-position `impl Trait` in trait cannot be specialized"
|
|
|
|
),
|
2023-09-13 16:04:42 +00:00
|
|
|
"return position `impl Trait` in traits",
|
2023-02-28 02:03:26 +00:00
|
|
|
)
|
|
|
|
};
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx()
|
2023-02-28 02:03:26 +00:00
|
|
|
.struct_span_err(tcx.def_span(def_id), msg)
|
2024-01-09 09:08:49 +11:00
|
|
|
.with_note(format!(
|
|
|
|
"specialization behaves in inconsistent and surprising ways with \
|
|
|
|
{feature}, and for now is disallowed"
|
2023-02-28 02:03:26 +00:00
|
|
|
))
|
|
|
|
.emit();
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2021-01-22 08:22:15 +01:00
|
|
|
if !missing_items.is_empty() {
|
2025-04-02 07:04:24 +11:00
|
|
|
let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));
|
2023-04-19 17:20:28 +00:00
|
|
|
missing_items_err(tcx, impl_id, &missing_items, full_impl_span);
|
2021-01-22 08:22:15 +01:00
|
|
|
}
|
2021-12-21 18:40:50 +03:00
|
|
|
|
|
|
|
if let Some(missing_items) = must_implement_one_of {
|
|
|
|
let attr_span = tcx
|
2024-03-05 20:19:05 +01:00
|
|
|
.get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of)
|
2025-02-09 22:49:28 +01:00
|
|
|
.map(|attr| attr.span());
|
2021-12-21 18:40:50 +03:00
|
|
|
|
2022-07-04 17:23:24 +09:00
|
|
|
missing_items_must_implement_one_of_err(
|
|
|
|
tcx,
|
|
|
|
tcx.def_span(impl_id),
|
|
|
|
missing_items,
|
|
|
|
attr_span,
|
|
|
|
);
|
2021-12-21 18:40:50 +03:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-27 13:14:50 +10:00
|
|
|
fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
|
2023-07-11 22:35:29 +01:00
|
|
|
let t = tcx.type_of(def_id).instantiate_identity();
|
|
|
|
if let ty::Adt(def, args) = t.kind()
|
2022-04-15 15:56:32 +09:00
|
|
|
&& def.is_struct()
|
|
|
|
{
|
|
|
|
let fields = &def.non_enum_variant().fields;
|
|
|
|
if fields.is_empty() {
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
|
2022-04-15 15:56:32 +09:00
|
|
|
return;
|
|
|
|
}
|
2024-08-22 01:28:20 -07:00
|
|
|
|
|
|
|
let array_field = &fields[FieldIdx::ZERO];
|
|
|
|
let array_ty = array_field.ty(tcx, args);
|
|
|
|
let ty::Array(element_ty, len_const) = array_ty.kind() else {
|
|
|
|
struct_span_code_err!(
|
|
|
|
tcx.dcx(),
|
|
|
|
sp,
|
|
|
|
E0076,
|
|
|
|
"SIMD vector's only field must be an array"
|
|
|
|
)
|
|
|
|
.with_span_label(tcx.def_span(array_field.did), "not an array")
|
|
|
|
.emit();
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) {
|
|
|
|
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields")
|
|
|
|
.with_span_label(tcx.def_span(second_field.did), "excess field")
|
2022-04-15 15:56:32 +09:00
|
|
|
.emit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-09-27 12:56:51 -04:00
|
|
|
// FIXME(repr_simd): This check is nice, but perhaps unnecessary due to the fact
|
|
|
|
// we do not expect users to implement their own `repr(simd)` types. If they could,
|
|
|
|
// this check is easily side-steppable by hiding the const behind normalization.
|
|
|
|
// The consequence is that the error is, in general, only observable post-mono.
|
|
|
|
if let Some(len) = len_const.try_to_target_usize(tcx) {
|
2022-04-15 15:56:32 +09:00
|
|
|
if len == 0 {
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
return;
|
2022-04-15 15:56:32 +09:00
|
|
|
} else if len > MAX_SIMD_LANES {
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2022-04-15 15:56:32 +09:00
|
|
|
sp,
|
|
|
|
E0075,
|
|
|
|
"SIMD vector cannot have more than {MAX_SIMD_LANES} elements",
|
|
|
|
)
|
|
|
|
.emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
return;
|
|
|
|
}
|
2022-04-15 15:56:32 +09:00
|
|
|
}
|
2021-01-02 23:49:28 -05:00
|
|
|
|
2022-04-15 15:56:32 +09:00
|
|
|
// Check that we use types valid for use in the lanes of a SIMD "vector register"
|
|
|
|
// These are scalar types which directly match a "machine" type
|
|
|
|
// Yes: Integers, floats, "thin" pointers
|
2024-10-03 15:05:23 +02:00
|
|
|
// No: char, "wide" pointers, compound types
|
2024-08-22 01:28:20 -07:00
|
|
|
match element_ty.kind() {
|
|
|
|
ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors
|
|
|
|
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok
|
2022-04-15 15:56:32 +09:00
|
|
|
_ => {
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2022-04-15 15:56:32 +09:00
|
|
|
sp,
|
|
|
|
E0077,
|
|
|
|
"SIMD vector element type should be a \
|
|
|
|
primitive scalar (integer/float/pointer) type"
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
return;
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-05 07:28:41 +11:00
|
|
|
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
|
|
|
|
let repr = def.repr();
|
2020-09-19 13:51:59 -07:00
|
|
|
if repr.packed() {
|
2025-02-09 22:49:33 +01:00
|
|
|
if let Some(reprs) =
|
|
|
|
attr::find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::Repr(r) => r)
|
|
|
|
{
|
|
|
|
for (r, _) in reprs {
|
|
|
|
if let ReprPacked(pack) = r
|
2022-05-02 09:31:56 +02:00
|
|
|
&& let Some(repr_pack) = repr.pack
|
2025-02-09 22:49:33 +01:00
|
|
|
&& pack != &repr_pack
|
2022-05-02 09:31:56 +02:00
|
|
|
{
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2022-05-02 09:31:56 +02:00
|
|
|
sp,
|
|
|
|
E0634,
|
|
|
|
"type has conflicting packed representation hints"
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if repr.align.is_some() {
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2020-09-19 13:51:59 -07:00
|
|
|
sp,
|
|
|
|
E0587,
|
|
|
|
"type has conflicting packed and align representation hints"
|
|
|
|
)
|
|
|
|
.emit();
|
2024-09-11 17:23:56 -04:00
|
|
|
} else if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) {
|
|
|
|
let mut err = struct_span_code_err!(
|
|
|
|
tcx.dcx(),
|
|
|
|
sp,
|
|
|
|
E0588,
|
|
|
|
"packed type cannot transitively contain a `#[repr(align)]` type"
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2024-09-11 17:23:56 -04:00
|
|
|
err.span_note(
|
|
|
|
tcx.def_span(def_spans[0].0),
|
|
|
|
format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2024-09-11 17:23:56 -04:00
|
|
|
if def_spans.len() > 2 {
|
|
|
|
let mut first = true;
|
|
|
|
for (adt_def, span) in def_spans.iter().skip(1).rev() {
|
|
|
|
let ident = tcx.item_name(*adt_def);
|
|
|
|
err.span_note(
|
|
|
|
*span,
|
|
|
|
if first {
|
|
|
|
format!(
|
|
|
|
"`{}` contains a field of type `{}`",
|
|
|
|
tcx.type_of(def.did()).instantiate_identity(),
|
|
|
|
ident
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!("...which contains a field of type `{ident}`")
|
|
|
|
},
|
|
|
|
);
|
|
|
|
first = false;
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2024-09-11 17:23:56 -04:00
|
|
|
|
|
|
|
err.emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn check_packed_inner(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
def_id: DefId,
|
|
|
|
stack: &mut Vec<DefId>,
|
|
|
|
) -> Option<Vec<(DefId, Span)>> {
|
2023-07-11 22:35:29 +01:00
|
|
|
if let ty::Adt(def, args) = tcx.type_of(def_id).instantiate_identity().kind() {
|
2020-09-19 13:51:59 -07:00
|
|
|
if def.is_struct() || def.is_union() {
|
2022-03-05 07:28:41 +11:00
|
|
|
if def.repr().align.is_some() {
|
|
|
|
return Some(vec![(def.did(), DUMMY_SP)]);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
stack.push(def_id);
|
|
|
|
for field in &def.non_enum_variant().fields {
|
2023-07-11 22:35:29 +01:00
|
|
|
if let ty::Adt(def, _) = field.ty(tcx, args).kind()
|
2022-04-15 15:56:32 +09:00
|
|
|
&& !stack.contains(&def.did())
|
|
|
|
&& let Some(mut defs) = check_packed_inner(tcx, def.did(), stack)
|
|
|
|
{
|
|
|
|
defs.push((def.did(), field.ident(tcx).span));
|
|
|
|
return Some(defs);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
stack.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
|
2022-03-05 07:28:41 +11:00
|
|
|
if !adt.repr().transparent() {
|
2020-09-19 13:51:59 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-10-09 09:01:57 +02:00
|
|
|
if adt.is_union() && !tcx.features().transparent_unions() {
|
2020-09-19 13:51:59 -07:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&tcx.sess,
|
2020-09-19 13:51:59 -07:00
|
|
|
sym::transparent_unions,
|
2022-10-30 18:31:03 +00:00
|
|
|
tcx.def_span(adt.did()),
|
2020-09-19 13:51:59 -07:00
|
|
|
"transparent unions are unstable",
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
|
2022-03-05 07:28:41 +11:00
|
|
|
if adt.variants().len() != 1 {
|
2022-10-30 18:31:03 +00:00
|
|
|
bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
|
2022-12-27 18:28:02 -08:00
|
|
|
// Don't bother checking the fields.
|
|
|
|
return;
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2023-08-29 08:58:38 +02:00
|
|
|
// For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
|
|
|
|
// "known" respecting #[non_exhaustive] attributes.
|
2020-09-19 13:51:59 -07:00
|
|
|
let field_infos = adt.all_fields().map(|field| {
|
2023-07-11 22:35:29 +01:00
|
|
|
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
|
2024-11-15 13:53:31 +01:00
|
|
|
let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did);
|
|
|
|
let layout = tcx.layout_of(typing_env.as_query_input(ty));
|
2020-09-19 13:51:59 -07:00
|
|
|
// We are currently checking the type this field came from, so it must be local
|
2025-04-02 07:04:24 +11:00
|
|
|
let span = tcx.hir_span_if_local(field.did).unwrap();
|
2023-08-29 08:58:38 +02:00
|
|
|
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
|
|
|
|
if !trivial {
|
|
|
|
return (span, trivial, None);
|
2022-07-07 16:55:41 +00:00
|
|
|
}
|
2023-08-29 08:58:38 +02:00
|
|
|
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`.
|
2022-07-07 16:55:41 +00:00
|
|
|
|
|
|
|
fn check_non_exhaustive<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
t: Ty<'tcx>,
|
2023-07-11 22:35:29 +01:00
|
|
|
) -> ControlFlow<(&'static str, DefId, GenericArgsRef<'tcx>, bool)> {
|
2022-07-07 16:55:41 +00:00
|
|
|
match t.kind() {
|
|
|
|
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
|
|
|
|
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
|
2024-02-12 15:39:32 +09:00
|
|
|
ty::Adt(def, args) => {
|
2024-08-24 20:39:26 +03:00
|
|
|
if !def.did().is_local() && !tcx.has_attr(def.did(), sym::rustc_pub_transparent)
|
|
|
|
{
|
2022-07-07 16:55:41 +00:00
|
|
|
let non_exhaustive = def.is_variant_list_non_exhaustive()
|
|
|
|
|| def
|
|
|
|
.variants()
|
|
|
|
.iter()
|
|
|
|
.any(ty::VariantDef::is_field_list_non_exhaustive);
|
|
|
|
let has_priv = def.all_fields().any(|f| !f.vis.is_public());
|
|
|
|
if non_exhaustive || has_priv {
|
|
|
|
return ControlFlow::Break((
|
|
|
|
def.descr(),
|
|
|
|
def.did(),
|
2024-02-12 15:39:32 +09:00
|
|
|
args,
|
2022-07-07 16:55:41 +00:00
|
|
|
non_exhaustive,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
def.all_fields()
|
2024-02-12 15:39:32 +09:00
|
|
|
.map(|field| field.ty(tcx, args))
|
2022-07-07 16:55:41 +00:00
|
|
|
.try_for_each(|t| check_non_exhaustive(tcx, t))
|
|
|
|
}
|
|
|
|
_ => ControlFlow::Continue(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-29 08:58:38 +02:00
|
|
|
(span, trivial, check_non_exhaustive(tcx, ty).break_value())
|
2020-09-19 13:51:59 -07:00
|
|
|
});
|
|
|
|
|
2023-08-29 08:58:38 +02:00
|
|
|
let non_trivial_fields = field_infos
|
2022-07-07 16:55:41 +00:00
|
|
|
.clone()
|
2023-08-29 08:58:38 +02:00
|
|
|
.filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
|
|
|
|
let non_trivial_count = non_trivial_fields.clone().count();
|
|
|
|
if non_trivial_count >= 2 {
|
|
|
|
bad_non_zero_sized_fields(
|
|
|
|
tcx,
|
|
|
|
adt,
|
|
|
|
non_trivial_count,
|
|
|
|
non_trivial_fields,
|
|
|
|
tcx.def_span(adt.did()),
|
|
|
|
);
|
|
|
|
return;
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2023-09-18 06:59:11 +00:00
|
|
|
let mut prev_non_exhaustive_1zst = false;
|
|
|
|
for (span, _trivial, non_exhaustive_1zst) in field_infos {
|
|
|
|
if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst {
|
|
|
|
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
|
|
|
|
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
|
|
|
|
if non_trivial_count > 0 || prev_non_exhaustive_1zst {
|
2024-01-16 16:14:33 +11:00
|
|
|
tcx.node_span_lint(
|
2023-09-18 06:59:11 +00:00
|
|
|
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
2023-11-24 19:28:19 +03:00
|
|
|
tcx.local_def_id_to_hir_id(adt.did().expect_local()),
|
2023-09-18 06:59:11 +00:00
|
|
|
span,
|
|
|
|
|lint| {
|
2024-05-22 16:46:05 +02:00
|
|
|
lint.primary_message(
|
|
|
|
"zero-sized fields in `repr(transparent)` cannot \
|
|
|
|
contain external non-exhaustive types",
|
|
|
|
);
|
2023-09-18 06:59:11 +00:00
|
|
|
let note = if non_exhaustive {
|
|
|
|
"is marked with `#[non_exhaustive]`"
|
|
|
|
} else {
|
|
|
|
"contains private fields"
|
|
|
|
};
|
|
|
|
let field_ty = tcx.def_path_str_with_args(def_id, args);
|
|
|
|
lint.note(format!(
|
|
|
|
"this {descr} contains `{field_ty}`, which {note}, \
|
|
|
|
and makes it not a breaking change to become \
|
|
|
|
non-zero-sized in the future."
|
2023-12-08 01:52:56 +00:00
|
|
|
));
|
2023-09-18 06:59:11 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
prev_non_exhaustive_1zst = true;
|
|
|
|
}
|
2022-07-07 16:55:41 +00:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(trivial_numeric_casts)]
|
2022-12-20 22:10:40 +01:00
|
|
|
fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
2020-09-19 13:51:59 -07:00
|
|
|
let def = tcx.adt_def(def_id);
|
|
|
|
def.destructor(tcx); // force the destructor to be evaluated
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
if def.variants().is_empty() {
|
2025-02-09 22:49:33 +01:00
|
|
|
attr::find_attr!(
|
|
|
|
tcx.get_all_attrs(def_id),
|
|
|
|
AttributeKind::Repr(rs) => {
|
|
|
|
struct_span_code_err!(
|
|
|
|
tcx.dcx(),
|
|
|
|
rs.first().unwrap().1,
|
|
|
|
E0084,
|
|
|
|
"unsupported representation for zero-variant enum"
|
|
|
|
)
|
|
|
|
.with_span_label(tcx.def_span(def_id), "zero-variant enum")
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2022-03-05 07:28:41 +11:00
|
|
|
let repr_type_ty = def.repr().discr_type().to_ty(tcx);
|
2020-09-19 13:51:59 -07:00
|
|
|
if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
|
2024-10-09 09:01:57 +02:00
|
|
|
if !tcx.features().repr128() {
|
2020-09-19 13:51:59 -07:00
|
|
|
feature_err(
|
2024-01-10 00:37:30 -05:00
|
|
|
&tcx.sess,
|
2020-09-19 13:51:59 -07:00
|
|
|
sym::repr128,
|
2022-10-30 18:31:03 +00:00
|
|
|
tcx.def_span(def_id),
|
2020-09-19 13:51:59 -07:00
|
|
|
"repr with 128-bit type is unstable",
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
for v in def.variants() {
|
|
|
|
if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
|
2025-01-30 16:20:09 +11:00
|
|
|
tcx.ensure_ok().typeck(discr_def_id.expect_local());
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
if def.repr().int.is_none() {
|
2022-10-25 20:15:15 +04:00
|
|
|
let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));
|
2022-10-30 18:31:03 +00:00
|
|
|
let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
let has_non_units = def.variants().iter().any(|var| !is_unit(var));
|
2023-11-21 20:07:32 +01:00
|
|
|
let disr_units = def.variants().iter().any(|var| is_unit(var) && has_disr(var));
|
|
|
|
let disr_non_unit = def.variants().iter().any(|var| !is_unit(var) && has_disr(var));
|
2020-09-19 13:51:59 -07:00
|
|
|
|
|
|
|
if disr_non_unit || (disr_units && has_non_units) {
|
2024-01-04 09:08:36 +11:00
|
|
|
struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2022-10-30 18:31:03 +00:00
|
|
|
tcx.def_span(def_id),
|
|
|
|
E0732,
|
|
|
|
"`#[repr(inttype)]` must be specified"
|
2024-01-03 17:03:10 +11:00
|
|
|
)
|
|
|
|
.emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
detect_discriminant_duplicate(tcx, def);
|
|
|
|
check_transparent(tcx, def);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2022-08-08 21:34:55 +02:00
|
|
|
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
|
2022-10-30 18:31:03 +00:00
|
|
|
fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
|
2022-08-08 21:34:55 +02:00
|
|
|
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
|
|
|
|
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
|
2024-02-23 10:20:45 +11:00
|
|
|
let report = |dis: Discr<'tcx>, idx, err: &mut Diag<'_>| {
|
2022-10-30 18:31:03 +00:00
|
|
|
let var = adt.variant(idx); // HIR for the duplicate discriminant
|
|
|
|
let (span, display_discr) = match var.discr {
|
|
|
|
ty::VariantDiscr::Explicit(discr_def_id) => {
|
2022-08-07 17:24:25 +02:00
|
|
|
// In the case the discriminant is both a duplicate and overflowed, let the user know
|
2022-10-30 18:31:03 +00:00
|
|
|
if let hir::Node::AnonConst(expr) =
|
2023-12-01 05:28:34 -08:00
|
|
|
tcx.hir_node_by_def_id(discr_def_id.expect_local())
|
2025-02-03 10:45:49 +11:00
|
|
|
&& let hir::ExprKind::Lit(lit) = &tcx.hir_body(expr.body).value.kind
|
2022-08-07 17:24:25 +02:00
|
|
|
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
|
|
|
|
&& *lit_value != dis.val
|
|
|
|
{
|
2022-10-30 18:31:03 +00:00
|
|
|
(tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
|
2022-08-07 17:24:25 +02:00
|
|
|
} else {
|
2022-10-30 18:31:03 +00:00
|
|
|
// Otherwise, format the value as-is
|
|
|
|
(tcx.def_span(discr_def_id), format!("`{dis}`"))
|
2022-08-07 17:24:25 +02:00
|
|
|
}
|
|
|
|
}
|
2022-10-30 18:31:03 +00:00
|
|
|
// This should not happen.
|
|
|
|
ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
|
|
|
|
ty::VariantDiscr::Relative(distance_to_explicit) => {
|
2022-08-07 22:28:16 +02:00
|
|
|
// At this point we know this discriminant is a duplicate, and was not explicitly
|
2022-08-07 23:50:12 +02:00
|
|
|
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
|
2022-08-18 10:13:37 +08:00
|
|
|
// explicitly assigned discriminant, and letting the user know that this was the
|
2022-08-07 22:28:16 +02:00
|
|
|
// increment startpoint, and how many steps from there leading to the duplicate
|
2022-10-30 18:31:03 +00:00
|
|
|
if let Some(explicit_idx) =
|
|
|
|
idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
|
2022-08-07 17:24:25 +02:00
|
|
|
{
|
2022-10-30 18:31:03 +00:00
|
|
|
let explicit_variant = adt.variant(explicit_idx);
|
|
|
|
let ve_ident = var.name;
|
|
|
|
let ex_ident = explicit_variant.name;
|
|
|
|
let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
|
2022-08-07 17:24:25 +02:00
|
|
|
|
|
|
|
err.span_label(
|
2022-10-30 18:31:03 +00:00
|
|
|
tcx.def_span(explicit_variant.def_id),
|
|
|
|
format!(
|
|
|
|
"discriminant for `{ve_ident}` incremented from this startpoint \
|
|
|
|
(`{ex_ident}` + {distance_to_explicit} {sp} later \
|
|
|
|
=> `{ve_ident}` = {dis})"
|
|
|
|
),
|
2022-08-07 17:24:25 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
(tcx.def_span(var.def_id), format!("`{dis}`"))
|
2022-08-07 17:24:25 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
err.span_label(span, format!("{display_discr} assigned here"));
|
|
|
|
};
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
|
|
|
|
|
2022-08-08 21:34:55 +02:00
|
|
|
// Here we loop through the discriminants, comparing each discriminant to another.
|
2022-08-18 10:13:37 +08:00
|
|
|
// When a duplicate is detected, we instantiate an error and point to both
|
2022-08-07 23:50:12 +02:00
|
|
|
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
|
|
|
|
// it with the last element and decrementing the `vec.len` (which is why we have to evaluate
|
|
|
|
// `discrs.len()` anew every iteration, and why this could be tricky to do in a functional
|
|
|
|
// style as we are mutating `discrs` on the fly).
|
2022-08-07 17:24:25 +02:00
|
|
|
let mut i = 0;
|
|
|
|
while i < discrs.len() {
|
2022-10-30 18:31:03 +00:00
|
|
|
let var_i_idx = discrs[i].0;
|
2024-02-23 10:20:45 +11:00
|
|
|
let mut error: Option<Diag<'_, _>> = None;
|
2022-08-07 17:24:25 +02:00
|
|
|
|
|
|
|
let mut o = i + 1;
|
|
|
|
while o < discrs.len() {
|
2022-10-30 18:31:03 +00:00
|
|
|
let var_o_idx = discrs[o].0;
|
2022-08-07 17:24:25 +02:00
|
|
|
|
|
|
|
if discrs[i].1.val == discrs[o].1.val {
|
|
|
|
let err = error.get_or_insert_with(|| {
|
2024-01-04 09:08:36 +11:00
|
|
|
let mut ret = struct_span_code_err!(
|
2023-12-18 22:21:37 +11:00
|
|
|
tcx.dcx(),
|
2022-10-30 18:31:03 +00:00
|
|
|
tcx.def_span(adt.did()),
|
2022-08-07 17:24:25 +02:00
|
|
|
E0081,
|
|
|
|
"discriminant value `{}` assigned more than once",
|
|
|
|
discrs[i].1,
|
|
|
|
);
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
report(discrs[i].1, var_i_idx, &mut ret);
|
2022-08-07 17:24:25 +02:00
|
|
|
|
|
|
|
ret
|
|
|
|
});
|
|
|
|
|
2022-10-30 18:31:03 +00:00
|
|
|
report(discrs[o].1, var_o_idx, err);
|
2022-08-07 17:24:25 +02:00
|
|
|
|
2022-08-07 22:28:16 +02:00
|
|
|
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
|
2022-08-07 17:24:25 +02:00
|
|
|
discrs[o] = *discrs.last().unwrap();
|
|
|
|
discrs.pop();
|
|
|
|
} else {
|
|
|
|
o += 1;
|
|
|
|
}
|
2021-07-15 21:25:11 +02:00
|
|
|
}
|
2022-05-27 15:42:15 +02:00
|
|
|
|
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
|
|
|
if let Some(e) = error {
|
2022-08-07 17:24:25 +02:00
|
|
|
e.emit();
|
|
|
|
}
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
}
|
2021-07-15 21:25:11 +02:00
|
|
|
}
|
|
|
|
|
2024-02-01 15:58:07 +01:00
|
|
|
fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
|
|
|
|
if tcx.type_alias_is_lazy(def_id) {
|
|
|
|
// Since we compute the variances for lazy type aliases and already reject bivariant
|
|
|
|
// parameters as unused, we can and should skip this check for lazy type aliases.
|
|
|
|
return;
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2024-02-01 15:58:07 +01:00
|
|
|
let generics = tcx.generics_of(def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
if generics.own_counts().types == 0 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-01 15:58:07 +01:00
|
|
|
let ty = tcx.type_of(def_id).instantiate_identity();
|
2020-09-19 13:51:59 -07:00
|
|
|
if ty.references_error() {
|
2024-02-01 15:58:07 +01:00
|
|
|
// If there is already another error, do not emit an error for not using a type parameter.
|
2020-09-19 13:51:59 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-01 15:58:07 +01:00
|
|
|
// Lazily calculated because it is only needed in case of an error.
|
|
|
|
let bounded_params = LazyCell::new(|| {
|
|
|
|
tcx.explicit_predicates_of(def_id)
|
|
|
|
.predicates
|
|
|
|
.iter()
|
|
|
|
.filter_map(|(predicate, span)| {
|
|
|
|
let bounded_ty = match predicate.kind().skip_binder() {
|
|
|
|
ty::ClauseKind::Trait(pred) => pred.trait_ref.self_ty(),
|
|
|
|
ty::ClauseKind::TypeOutlives(pred) => pred.0,
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
if let ty::Param(param) = bounded_ty.kind() {
|
|
|
|
Some((param.index, span))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
// FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the
|
|
|
|
// time of writing). This is a bit fragile since we later use the span to detect elaborated
|
|
|
|
// `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized`
|
|
|
|
// since it would overwrite the span of the user-written bound. This could be fixed by
|
|
|
|
// folding the spans with `Span::to` which requires a bit of effort I think.
|
2024-02-11 19:50:50 +08:00
|
|
|
.collect::<FxIndexMap<_, _>>()
|
2024-02-01 15:58:07 +01:00
|
|
|
});
|
|
|
|
|
2025-01-07 15:19:05 +00:00
|
|
|
let mut params_used = DenseBitSet::new_empty(generics.own_params.len());
|
2022-01-12 03:19:52 +00:00
|
|
|
for leaf in ty.walk() {
|
2022-04-15 15:56:32 +09:00
|
|
|
if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
|
|
|
|
&& let ty::Param(param) = leaf_ty.kind()
|
|
|
|
{
|
|
|
|
debug!("found use of ty param {:?}", param);
|
|
|
|
params_used.insert(param.index);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
for param in &generics.own_params {
|
2022-04-15 15:56:32 +09:00
|
|
|
if !params_used.contains(param.index)
|
|
|
|
&& let ty::GenericParamDefKind::Type { .. } = param.kind
|
|
|
|
{
|
|
|
|
let span = tcx.def_span(param.def_id);
|
2024-02-01 15:58:07 +01:00
|
|
|
let param_name = Ident::new(param.name, span);
|
|
|
|
|
|
|
|
// The corresponding predicates are post-`Sized`-elaboration. Therefore we
|
|
|
|
// * check for emptiness to detect lone user-written `?Sized` bounds
|
|
|
|
// * compare the param span to the pred span to detect lone user-written `Sized` bounds
|
|
|
|
let has_explicit_bounds = bounded_params.is_empty()
|
|
|
|
|| (*bounded_params).get(¶m.index).is_some_and(|&&pred_sp| pred_sp != span);
|
2024-08-21 00:57:58 -04:00
|
|
|
let const_param_help = !has_explicit_bounds;
|
2024-02-01 15:58:07 +01:00
|
|
|
|
|
|
|
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
|
2024-01-04 09:08:36 +11:00
|
|
|
span,
|
2024-02-01 15:58:07 +01:00
|
|
|
param_name,
|
|
|
|
param_def_kind: tcx.def_descr(param.def_id),
|
|
|
|
help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
|
2024-07-17 18:05:21 -04:00
|
|
|
usage_spans: vec![],
|
2024-02-01 15:58:07 +01:00
|
|
|
const_param_help,
|
|
|
|
});
|
|
|
|
diag.code(E0091);
|
|
|
|
diag.emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit an error for recursive opaque types.
|
|
|
|
///
|
|
|
|
/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
|
|
|
|
/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
|
|
|
|
/// `impl Trait`.
|
|
|
|
///
|
|
|
|
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
|
|
|
|
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
|
2024-11-08 03:46:23 +00:00
|
|
|
fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorGuaranteed {
|
|
|
|
let span = tcx.def_span(opaque_def_id);
|
2024-01-04 09:08:36 +11:00
|
|
|
let mut err = struct_span_code_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type");
|
2020-09-19 13:51:59 -07:00
|
|
|
|
|
|
|
let mut label = false;
|
2023-01-08 00:29:30 +00:00
|
|
|
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
|
2021-10-21 19:41:47 +02:00
|
|
|
let typeck_results = tcx.typeck(def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
if visitor
|
|
|
|
.returns
|
|
|
|
.iter()
|
|
|
|
.filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
|
|
|
|
.all(|ty| matches!(ty.kind(), ty::Never))
|
|
|
|
{
|
|
|
|
let spans = visitor
|
|
|
|
.returns
|
|
|
|
.iter()
|
|
|
|
.filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some())
|
|
|
|
.map(|expr| expr.span)
|
|
|
|
.collect::<Vec<Span>>();
|
|
|
|
let span_len = spans.len();
|
|
|
|
if span_len == 1 {
|
|
|
|
err.span_label(spans[0], "this returned value is of `!` type");
|
|
|
|
} else {
|
|
|
|
let mut multispan: MultiSpan = spans.clone().into();
|
|
|
|
for span in spans {
|
2022-06-29 21:16:43 +09:00
|
|
|
multispan.push_span_label(span, "this returned value is of `!` type");
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
err.span_note(multispan, "these returned values have a concrete \"never\" type");
|
|
|
|
}
|
|
|
|
err.help("this error will resolve once the item's body returns a concrete type");
|
|
|
|
} else {
|
|
|
|
let mut seen = FxHashSet::default();
|
|
|
|
seen.insert(span);
|
|
|
|
err.span_label(span, "recursive opaque type");
|
|
|
|
label = true;
|
|
|
|
for (sp, ty) in visitor
|
|
|
|
.returns
|
|
|
|
.iter()
|
|
|
|
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
|
|
|
|
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
|
|
|
|
{
|
2023-01-08 00:29:30 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
struct OpaqueTypeCollector {
|
|
|
|
opaques: Vec<DefId>,
|
|
|
|
closures: Vec<DefId>,
|
|
|
|
}
|
2025-03-13 17:09:25 +00:00
|
|
|
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector {
|
2024-02-24 17:22:28 -05:00
|
|
|
fn visit_ty(&mut self, t: Ty<'tcx>) {
|
2020-09-19 13:51:59 -07:00
|
|
|
match *t.kind() {
|
2022-12-13 11:07:42 +00:00
|
|
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
2023-01-08 00:29:30 +00:00
|
|
|
self.opaques.push(def);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2023-10-19 16:06:43 +00:00
|
|
|
ty::Closure(def_id, ..) | ty::Coroutine(def_id, ..) => {
|
2023-01-08 00:29:30 +00:00
|
|
|
self.closures.push(def_id);
|
2024-02-24 17:22:28 -05:00
|
|
|
t.super_visit_with(self);
|
2023-01-08 00:29:30 +00:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
_ => t.super_visit_with(self),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-08 00:29:30 +00:00
|
|
|
|
|
|
|
let mut visitor = OpaqueTypeCollector::default();
|
2020-09-19 13:51:59 -07:00
|
|
|
ty.visit_with(&mut visitor);
|
2023-01-08 00:29:30 +00:00
|
|
|
for def_id in visitor.opaques {
|
2020-09-19 13:51:59 -07:00
|
|
|
let ty_span = tcx.def_span(def_id);
|
|
|
|
if !seen.contains(&ty_span) {
|
2022-10-01 15:57:22 +02:00
|
|
|
let descr = if ty.is_impl_trait() { "opaque " } else { "" };
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.span_label(ty_span, format!("returning this {descr}type `{ty}`"));
|
2020-09-19 13:51:59 -07:00
|
|
|
seen.insert(ty_span);
|
|
|
|
}
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.span_label(sp, format!("returning here with type `{ty}`"));
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2023-01-08 00:29:30 +00:00
|
|
|
|
|
|
|
for closure_def_id in visitor.closures {
|
2023-07-07 15:24:10 -03:00
|
|
|
let Some(closure_local_did) = closure_def_id.as_local() else {
|
|
|
|
continue;
|
|
|
|
};
|
2023-01-08 00:29:30 +00:00
|
|
|
let typeck_results = tcx.typeck(closure_local_did);
|
|
|
|
|
|
|
|
let mut label_match = |ty: Ty<'_>, span| {
|
|
|
|
for arg in ty.walk() {
|
|
|
|
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
|
|
|
&& let ty::Alias(
|
|
|
|
ty::Opaque,
|
|
|
|
ty::AliasTy { def_id: captured_def_id, .. },
|
|
|
|
) = *ty.kind()
|
|
|
|
&& captured_def_id == opaque_def_id.to_def_id()
|
|
|
|
{
|
|
|
|
err.span_label(
|
|
|
|
span,
|
|
|
|
format!(
|
|
|
|
"{} captures itself here",
|
2023-02-21 14:05:32 -07:00
|
|
|
tcx.def_descr(closure_def_id)
|
2023-01-08 00:29:30 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Label any closure upvars that capture the opaque
|
|
|
|
for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
|
|
|
|
{
|
|
|
|
label_match(capture.place.ty(), capture.get_path_span(tcx));
|
|
|
|
}
|
2023-10-19 21:46:28 +00:00
|
|
|
// Label any coroutine locals that capture the opaque
|
2023-11-26 21:05:08 +08:00
|
|
|
if tcx.is_coroutine(closure_def_id)
|
2023-10-19 21:46:28 +00:00
|
|
|
&& let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id)
|
2023-01-28 22:45:52 +00:00
|
|
|
{
|
2023-10-19 21:46:28 +00:00
|
|
|
for interior_ty in &coroutine_layout.field_tys {
|
2023-01-28 22:45:52 +00:00
|
|
|
label_match(interior_ty.ty, interior_ty.source_info.span);
|
|
|
|
}
|
|
|
|
}
|
2023-01-08 00:29:30 +00:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !label {
|
|
|
|
err.span_label(span, "cannot resolve opaque type");
|
|
|
|
}
|
2022-01-22 18:49:12 -06:00
|
|
|
err.emit()
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-10-01 15:57:22 +02:00
|
|
|
|
2023-11-22 03:43:59 +00:00
|
|
|
pub(super) fn check_coroutine_obligations(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
def_id: LocalDefId,
|
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2024-04-15 19:44:23 -04:00
|
|
|
debug_assert!(!tcx.is_typeck_child(def_id.to_def_id()));
|
2022-10-01 15:57:22 +02:00
|
|
|
|
2024-04-15 19:44:23 -04:00
|
|
|
let typeck_results = tcx.typeck(def_id);
|
|
|
|
let param_env = tcx.param_env(def_id);
|
2022-10-01 15:57:22 +02:00
|
|
|
|
2024-04-15 19:44:23 -04:00
|
|
|
debug!(?typeck_results.coroutine_stalled_predicates);
|
2022-10-01 15:57:22 +02:00
|
|
|
|
2024-12-25 01:27:21 +00:00
|
|
|
let mode = if tcx.next_trait_solver_globally() {
|
|
|
|
TypingMode::post_borrowck_analysis(tcx, def_id)
|
|
|
|
} else {
|
|
|
|
TypingMode::analysis_in_body(tcx, def_id)
|
|
|
|
};
|
|
|
|
|
2022-10-01 15:57:22 +02:00
|
|
|
let infcx = tcx
|
|
|
|
.infer_ctxt()
|
|
|
|
// typeck writeback gives us predicates with their regions erased.
|
|
|
|
// As borrowck already has checked lifetimes, we do not need to do it again.
|
|
|
|
.ignoring_regions()
|
2024-12-25 01:27:21 +00:00
|
|
|
.build(mode);
|
2022-10-01 15:57:22 +02:00
|
|
|
|
2024-06-01 14:51:31 -04:00
|
|
|
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
2024-04-15 19:44:23 -04:00
|
|
|
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
|
|
|
|
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
|
2023-09-23 04:03:24 +00:00
|
|
|
}
|
|
|
|
|
2024-04-15 19:44:23 -04:00
|
|
|
let errors = ocx.select_all_or_error();
|
2022-10-01 15:57:22 +02:00
|
|
|
debug!(?errors);
|
|
|
|
if !errors.is_empty() {
|
2023-11-22 03:43:59 +00:00
|
|
|
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
|
2022-10-01 15:57:22 +02:00
|
|
|
}
|
2023-11-22 03:43:59 +00:00
|
|
|
|
2024-12-25 01:27:21 +00:00
|
|
|
if !tcx.next_trait_solver_globally() {
|
|
|
|
// Check that any hidden types found when checking these stalled coroutine obligations
|
|
|
|
// are valid.
|
|
|
|
for (key, ty) in infcx.take_opaque_types() {
|
2025-01-13 14:14:57 +01:00
|
|
|
let hidden_type = infcx.resolve_vars_if_possible(ty);
|
2024-12-25 01:27:21 +00:00
|
|
|
let key = infcx.resolve_vars_if_possible(key);
|
|
|
|
sanity_check_found_hidden_type(tcx, key, hidden_type)?;
|
|
|
|
}
|
2023-11-22 03:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2022-10-01 15:57:22 +02:00
|
|
|
}
|