2022-07-07 16:14:27 +02:00
|
|
|
use crate::check::intrinsicck::InlineAsmCtxt;
|
2023-03-07 22:26:52 +00:00
|
|
|
use crate::errors::{self, LinkageType};
|
2022-07-07 16:14:27 +02:00
|
|
|
|
2022-12-24 21:36:07 +00:00
|
|
|
use super::compare_impl_item::check_type_bounds;
|
|
|
|
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
|
2020-09-19 13:51:59 -07:00
|
|
|
use super::*;
|
|
|
|
use rustc_attr as attr;
|
2023-09-08 03:00:59 +00:00
|
|
|
use rustc_errors::{ErrorGuaranteed, MultiSpan};
|
2020-09-19 13:51:59 -07:00
|
|
|
use rustc_hir as hir;
|
2023-09-08 03:00:59 +00:00
|
|
|
use rustc_hir::def::{CtorKind, DefKind};
|
2023-04-26 20:53:51 +02:00
|
|
|
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
2023-09-08 03:00:59 +00:00
|
|
|
use rustc_hir::Node;
|
2022-06-27 18:46:16 +02:00
|
|
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
2023-05-09 20:18:22 +00:00
|
|
|
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
2022-10-01 15:57:22 +02:00
|
|
|
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
|
2023-04-16 11:48:01 +02:00
|
|
|
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
2022-04-27 18:14:19 +04:00
|
|
|
use rustc_middle::middle::stability::EvalResult;
|
2023-09-23 04:03:24 +00:00
|
|
|
use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
|
2023-07-20 09:36:02 +00:00
|
|
|
use rustc_middle::ty::fold::BottomUpFolder;
|
2022-02-24 14:10:41 -05:00
|
|
|
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
2021-04-27 15:01:37 +02:00
|
|
|
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
2023-07-11 22:35:29 +01:00
|
|
|
use rustc_middle::ty::GenericArgKind;
|
2023-02-12 21:08:14 +00:00
|
|
|
use rustc_middle::ty::{
|
2023-07-20 09:36:02 +00:00
|
|
|
self, AdtDef, ParamEnv, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
|
|
|
TypeVisitableExt,
|
2023-02-12 21:08:14 +00:00
|
|
|
};
|
2021-06-11 14:22:13 +03:00
|
|
|
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
2020-09-19 13:51:59 -07:00
|
|
|
use rustc_span::symbol::sym;
|
2022-03-24 02:03:04 +00:00
|
|
|
use rustc_span::{self, Span};
|
2023-03-28 23:32:25 -07:00
|
|
|
use rustc_target::abi::FieldIdx;
|
2020-09-19 13:51:59 -07:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2022-11-07 08:10:25 +01:00
|
|
|
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
|
2022-09-09 15:08:06 -05:00
|
|
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
2022-12-22 14:36:09 +03:00
|
|
|
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
2022-10-01 15:57:22 +02:00
|
|
|
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
|
2023-07-20 09:36:02 +00:00
|
|
|
use rustc_type_ir::fold::TypeFoldable;
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2020-10-21 14:26:34 +02:00
|
|
|
use std::ops::ControlFlow;
|
|
|
|
|
2022-10-20 17:51:37 +02:00
|
|
|
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
|
2021-06-11 14:22:13 +03:00
|
|
|
match tcx.sess.target.is_abi_supported(abi) {
|
|
|
|
Some(true) => (),
|
2022-01-27 09:44:25 +00:00
|
|
|
Some(false) => {
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
span,
|
|
|
|
E0570,
|
2022-04-15 15:56:32 +09:00
|
|
|
"`{abi}` is not a supported ABI for the current target",
|
2022-01-27 09:44:25 +00:00
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
2021-06-11 14:22:13 +03:00
|
|
|
None => {
|
2022-09-16 11:01:02 +04:00
|
|
|
tcx.struct_span_lint_hir(
|
|
|
|
UNSUPPORTED_CALLING_CONVENTIONS,
|
|
|
|
hir_id,
|
|
|
|
span,
|
|
|
|
"use of calling convention not supported on this target",
|
|
|
|
|lint| lint,
|
|
|
|
);
|
2021-06-11 14:22:13 +03:00
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2021-01-24 17:15:05 +00:00
|
|
|
|
|
|
|
// This ABI is only allowed on function pointers
|
|
|
|
if abi == Abi::CCmseNonSecureCall {
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
span,
|
|
|
|
E0781,
|
2021-10-03 14:28:39 +09:00
|
|
|
"the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
|
2021-01-24 17:15:05 +00:00
|
|
|
)
|
2022-01-27 09:44:25 +00:00
|
|
|
.emit();
|
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);
|
|
|
|
}
|
|
|
|
|
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 {
|
2023-07-11 22:35:29 +01:00
|
|
|
let item_type = tcx.type_of(item_def_id).instantiate_identity();
|
|
|
|
if let ty::Adt(def, args) = item_type.kind() {
|
2020-09-19 13:51:59 -07:00
|
|
|
assert!(def.is_union());
|
2022-06-29 22:33:18 -04:00
|
|
|
|
|
|
|
fn allowed_union_field<'tcx>(
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
) -> bool {
|
|
|
|
// We don't just accept all !needs_drop fields, due to semver concerns.
|
|
|
|
match ty.kind() {
|
|
|
|
ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
|
|
|
|
ty::Tuple(tys) => {
|
|
|
|
// allow tuples of allowed types
|
2022-12-18 13:51:40 +01:00
|
|
|
tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env))
|
2022-06-29 22:33:18 -04:00
|
|
|
}
|
|
|
|
ty::Array(elem, _len) => {
|
|
|
|
// Like `Copy`, we do *not* special-case length 0.
|
2022-12-18 13:51:40 +01:00
|
|
|
allowed_union_field(*elem, tcx, param_env)
|
2022-06-29 22:33:18 -04:00
|
|
|
}
|
|
|
|
_ => {
|
2023-03-07 22:03:12 +00:00
|
|
|
// Fallback case: allow `ManuallyDrop` and things that are `Copy`,
|
|
|
|
// also no need to report an error if the type is unresolved.
|
2022-06-30 10:17:49 -04:00
|
|
|
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
|
2022-10-27 14:45:02 +04:00
|
|
|
|| ty.is_copy_modulo_regions(tcx, param_env)
|
2023-03-07 22:03:12 +00:00
|
|
|
|| ty.references_error()
|
2022-06-29 22:33:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-19 13:51:59 -07:00
|
|
|
let param_env = tcx.param_env(item_def_id);
|
2022-06-29 22:33:18 -04:00
|
|
|
for field in &def.non_enum_variant().fields {
|
2023-07-11 22:35:29 +01:00
|
|
|
let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args));
|
2022-06-29 22:33:18 -04:00
|
|
|
|
2022-12-18 13:51:40 +01:00
|
|
|
if !allowed_union_field(field_ty, tcx, param_env) {
|
2021-11-15 14:47:36 +11:00
|
|
|
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
|
|
|
|
// 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"),
|
|
|
|
};
|
2023-03-07 22:26:52 +00:00
|
|
|
tcx.sess.emit_err(errors::InvalidUnionField {
|
2020-09-19 13:51:59 -07:00
|
|
|
field_span,
|
2023-03-07 22:26:52 +00:00
|
|
|
sugg: errors::InvalidUnionFieldSuggestion {
|
|
|
|
lo: ty_span.shrink_to_lo(),
|
|
|
|
hi: ty_span.shrink_to_hi(),
|
|
|
|
},
|
|
|
|
note: (),
|
|
|
|
});
|
2020-09-19 13:51:59 -07:00
|
|
|
return false;
|
2022-06-29 22:33:18 -04:00
|
|
|
} else if field_ty.needs_drop(tcx, param_env) {
|
|
|
|
// This should never happen. But we can get here e.g. in case of name resolution errors.
|
|
|
|
tcx.sess.delay_span_bug(span, "we should never accept maybe-dropping union fields");
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind());
|
|
|
|
}
|
|
|
|
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);
|
2022-02-24 14:10:41 -05:00
|
|
|
let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) {
|
|
|
|
Ok(l) => l,
|
|
|
|
// Foreign statics that overflow their allowed size should emit an error
|
|
|
|
Err(LayoutError::SizeOverflow(_))
|
2023-02-12 21:08:14 +00:00
|
|
|
if matches!(tcx.def_kind(def_id), DefKind::Static(_)
|
|
|
|
if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
|
2022-02-24 14:10:41 -05:00
|
|
|
{
|
2023-04-10 16:04:14 +01:00
|
|
|
tcx.sess.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-05-17 10:30:14 +00:00
|
|
|
tcx.sess.delay_span_bug(span, format!("{e:?}"));
|
2022-02-24 14:10:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2020-10-24 16:13:39 +02:00
|
|
|
};
|
|
|
|
if layout.abi.is_uninhabited() {
|
|
|
|
tcx.struct_span_lint_hir(
|
|
|
|
UNINHABITED_STATIC,
|
|
|
|
tcx.hir().local_def_id_to_hir_id(def_id),
|
|
|
|
span,
|
2022-09-16 11:01:02 +04:00
|
|
|
"static of uninhabited type",
|
2020-10-24 16:13:39 +02:00
|
|
|
|lint| {
|
2022-09-16 11:01:02 +04:00
|
|
|
lint
|
2020-10-24 16:13:39 +02:00
|
|
|
.note("uninhabited statics cannot be initialized, and any access would be an immediate error")
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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".
|
2022-12-20 22:10:40 +01:00
|
|
|
fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
2022-09-30 19:16:13 +00:00
|
|
|
let item = tcx.hir().item(id);
|
|
|
|
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
|
2023-02-12 21:08:14 +00:00
|
|
|
tcx.sess.delay_span_bug(item.span, "expected opaque item");
|
2022-09-30 19:16:13 +00:00
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
let args = GenericArgs::identity_for_item(tcx, item.owner_id);
|
2022-10-27 14:02:18 +11:00
|
|
|
let span = tcx.def_span(item.owner_id.def_id);
|
2022-09-30 19:16:13 +00:00
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
|
2020-06-28 16:46:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
if check_opaque_for_cycles(tcx, item.owner_id.def_id, args, span, &origin).is_err() {
|
2022-09-30 19:16:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-06-27 23:13:39 +02:00
|
|
|
|
|
|
|
let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &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,
|
2023-07-11 22:35:29 +01:00
|
|
|
args: GenericArgsRef<'tcx>,
|
2020-09-19 13:51:59 -07:00
|
|
|
span: Span,
|
|
|
|
origin: &hir::OpaqueTyOrigin,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2023-07-11 22:35:29 +01:00
|
|
|
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {
|
2022-01-22 18:49:12 -06:00
|
|
|
let reported = match origin {
|
2021-11-30 19:11:35 +01:00
|
|
|
hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span),
|
2020-09-19 13:51:59 -07:00
|
|
|
_ => opaque_type_cycle_error(tcx, def_id, span),
|
2022-01-22 18:49:12 -06:00
|
|
|
};
|
|
|
|
Err(reported)
|
2020-06-28 16:46:02 +01:00
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
span: Span,
|
|
|
|
origin: &hir::OpaqueTyOrigin,
|
2023-06-27 23:13:39 +02:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2021-12-01 16:34:40 +00:00
|
|
|
let defining_use_anchor = match *origin {
|
|
|
|
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
2023-04-25 11:43:08 +00:00
|
|
|
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
|
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
|
|
|
|
2022-07-02 16:37:49 +03:00
|
|
|
let infcx = tcx
|
|
|
|
.infer_ctxt()
|
|
|
|
.with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
|
2022-09-19 22:03:59 -05:00
|
|
|
.build();
|
2022-07-02 16:37:49 +03:00
|
|
|
let ocx = ObligationCtxt::new(&infcx);
|
2022-12-22 14:36:09 +03:00
|
|
|
|
2023-08-07 23:54:04 +00:00
|
|
|
let args = match *origin {
|
|
|
|
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
|
|
|
|
GenericArgs::identity_for_item(tcx, parent).extend_to(
|
2023-08-07 08:33:25 +00:00
|
|
|
tcx,
|
2023-08-07 23:54:04 +00:00
|
|
|
def_id.to_def_id(),
|
|
|
|
|param, _| tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id),
|
|
|
|
};
|
|
|
|
|
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-07-11 22:35:29 +01:00
|
|
|
// `ReErased` regions appear in the "parent_args" of closures/generators.
|
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);
|
2022-10-13 13:49:38 +03:00
|
|
|
let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
|
|
|
|
ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
|
|
|
|
_ => re,
|
|
|
|
});
|
|
|
|
|
2023-01-15 12:58:46 +01:00
|
|
|
let misc_cause = traits::ObligationCause::misc(span, def_id);
|
2022-09-19 22:03:59 -05:00
|
|
|
|
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) => {
|
2023-01-06 00:53:31 +00:00
|
|
|
let ty_err = ty_err.to_string(tcx);
|
2023-06-27 23:13:39 +02:00
|
|
|
return Err(tcx.sess.delay_span_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}"),
|
2023-06-27 23:13:39 +02:00
|
|
|
));
|
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
|
|
|
}
|
2022-07-02 16:37:49 +03:00
|
|
|
match origin {
|
|
|
|
// Checked when type checking the function containing them.
|
2023-09-14 15:16:48 +00:00
|
|
|
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
|
|
|
|
// 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();
|
|
|
|
return Ok(());
|
|
|
|
}
|
2022-12-22 14:36:09 +03:00
|
|
|
// Nested opaque types occur only in associated types:
|
|
|
|
// ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
|
|
|
|
// They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
|
|
|
|
// We don't have to check them here because their well-formedness follows from the WF of
|
|
|
|
// the projection input types in the defining- and use-sites.
|
2023-04-17 10:19:41 +00:00
|
|
|
hir::OpaqueTyOrigin::TyAlias { .. }
|
2022-12-22 14:36:09 +03:00
|
|
|
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
|
2022-07-02 16:37:49 +03:00
|
|
|
// Can have different predicates to their defining use
|
2023-04-17 10:19:41 +00:00
|
|
|
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
2023-06-27 23:13:39 +02:00
|
|
|
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
|
2022-12-22 14:36:09 +03:00
|
|
|
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
|
|
|
|
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
2023-06-27 23:13:39 +02:00
|
|
|
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
|
2022-07-02 16:37:49 +03:00
|
|
|
}
|
2022-09-19 22:03:59 -05:00
|
|
|
}
|
2023-07-20 09:36:02 +00:00
|
|
|
// Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
|
2023-08-07 08:33:25 +00:00
|
|
|
for (mut key, mut ty) in infcx.take_opaque_types() {
|
2023-07-20 09:36:02 +00:00
|
|
|
ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty);
|
2023-08-07 08:33:25 +00:00
|
|
|
key = infcx.resolve_vars_if_possible(key);
|
|
|
|
sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?;
|
2023-07-20 09:36:02 +00:00
|
|
|
}
|
2023-06-27 23:13:39 +02:00
|
|
|
Ok(())
|
2020-09-19 13:51:59 -07: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 };
|
|
|
|
Err(ty.report_mismatch(&other, key.def_id, tcx).emit())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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() {
|
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
|
|
|
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,
|
|
|
|
} {
|
|
|
|
tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-20 22:10:40 +01:00
|
|
|
fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
2020-09-19 13:51:59 -07:00
|
|
|
debug!(
|
2021-01-30 17:47:51 +01:00
|
|
|
"check_item_type(it.def_id={:?}, it.name={})",
|
2022-10-27 14:02:18 +11:00
|
|
|
id.owner_id,
|
2023-02-16 09:25:11 +00:00
|
|
|
tcx.def_path_str(id.owner_id)
|
2020-09-19 13:51:59 -07:00
|
|
|
);
|
|
|
|
let _indenter = indenter();
|
2022-10-27 14:02:18 +11:00
|
|
|
match tcx.def_kind(id.owner_id) {
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Static(..) => {
|
2022-10-27 14:02:18 +11:00
|
|
|
tcx.ensure().typeck(id.owner_id.def_id);
|
|
|
|
maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
|
|
|
|
check_static_inhabited(tcx, id.owner_id.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
|
|
|
check_static_linkage(tcx, id.owner_id.def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Const => {
|
2022-10-27 14:02:18 +11:00
|
|
|
tcx.ensure().typeck(id.owner_id.def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Enum => {
|
2022-10-30 18:31:03 +00:00
|
|
|
check_enum(tcx, id.owner_id.def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Fn => {} // entirely within check_item_body
|
2023-02-12 18:26:47 +00:00
|
|
|
DefKind::Impl { of_trait } => {
|
2023-02-12 18:49:54 +00:00
|
|
|
if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(id.owner_id) {
|
2020-11-22 17:46:21 -05:00
|
|
|
check_impl_items_against_trait(
|
|
|
|
tcx,
|
2023-02-12 18:49:54 +00:00
|
|
|
id.owner_id.def_id,
|
2023-07-11 22:35:29 +01:00
|
|
|
impl_trait_ref.instantiate_identity(),
|
2020-11-22 17:46:21 -05:00
|
|
|
);
|
2023-02-12 18:49:54 +00:00
|
|
|
check_on_unimplemented(tcx, id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Trait => {
|
2023-02-12 18:49:54 +00:00
|
|
|
let assoc_items = tcx.associated_items(id.owner_id);
|
|
|
|
check_on_unimplemented(tcx, id);
|
|
|
|
|
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();
|
|
|
|
fn_maybe_err(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-07-11 22:35:29 +01:00
|
|
|
let trait_args = GenericArgs::identity_for_item(tcx, id.owner_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,
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::TraitRef::new(tcx, id.owner_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 => {
|
2022-10-27 14:02:18 +11:00
|
|
|
check_struct(tcx, id.owner_id.def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Union => {
|
2022-10-27 14:02:18 +11:00
|
|
|
check_union(tcx, id.owner_id.def_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::OpaqueTy => {
|
2023-06-15 07:40:17 +00:00
|
|
|
let origin = tcx.opaque_type_origin(id.owner_id.def_id);
|
|
|
|
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id)
|
|
|
|
| hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
|
2023-03-20 17:05:46 +00:00
|
|
|
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
|
|
|
|
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
|
|
|
|
{
|
|
|
|
// Skip opaques from RPIT in traits with no default body.
|
|
|
|
} else {
|
|
|
|
check_opaque(tcx, id);
|
|
|
|
}
|
2022-09-30 19:16:13 +00:00
|
|
|
}
|
2023-09-26 02:15:32 +00:00
|
|
|
DefKind::TyAlias => {
|
2023-07-11 22:35:29 +01:00
|
|
|
let pty_ty = tcx.type_of(id.owner_id).instantiate_identity();
|
2022-10-27 14:02:18 +11:00
|
|
|
let generics = tcx.generics_of(id.owner_id);
|
2020-09-19 13:51:59 -07:00
|
|
|
check_type_params_are_used(tcx, &generics, pty_ty);
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::ForeignMod => {
|
|
|
|
let it = tcx.hir().item(id);
|
|
|
|
let hir::ItemKind::ForeignMod { abi, items } = it.kind else {
|
|
|
|
return;
|
|
|
|
};
|
2021-06-11 14:22:13 +03:00
|
|
|
check_abi(tcx, it.hir_id(), it.span, abi);
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2023-01-30 11:03:32 +00:00
|
|
|
match abi {
|
|
|
|
Abi::RustIntrinsic => {
|
|
|
|
for item in items {
|
|
|
|
let item = tcx.hir().foreign_item(item.id);
|
|
|
|
intrinsic::check_intrinsic_type(tcx, item);
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2023-01-30 11:03:32 +00:00
|
|
|
|
|
|
|
Abi::PlatformIntrinsic => {
|
|
|
|
for item in items {
|
|
|
|
let item = tcx.hir().foreign_item(item.id);
|
|
|
|
intrinsic::check_platform_intrinsic_type(tcx, item);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
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();
|
|
|
|
if generics.params.len() - own_counts.lifetimes != 0 {
|
|
|
|
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),
|
|
|
|
};
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
item.span,
|
|
|
|
E0044,
|
|
|
|
"foreign items may not have {kinds} parameters",
|
|
|
|
)
|
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
|
|
|
.span_label(item.span, format!("can't have {kinds} parameters"))
|
2023-01-30 11:03:32 +00:00
|
|
|
.help(
|
|
|
|
// 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
|
|
|
|
|
|
|
let item = tcx.hir().foreign_item(item.id);
|
|
|
|
match &item.kind {
|
|
|
|
hir::ForeignItemKind::Fn(fn_decl, _, _) => {
|
|
|
|
require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
|
|
|
|
}
|
|
|
|
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-14 12:07:36 +00:00
|
|
|
DefKind::GlobalAsm => {
|
|
|
|
let it = tcx.hir().item(id);
|
|
|
|
let hir::ItemKind::GlobalAsm(asm) = it.kind else {
|
|
|
|
span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
|
|
|
|
};
|
2022-11-05 15:33:58 +00:00
|
|
|
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
|
2022-04-14 12:07:36 +00:00
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
_ => {}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 18:49:54 +00:00
|
|
|
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: hir::ItemId) {
|
2020-09-19 13:51:59 -07:00
|
|
|
// an error would be reported if this fails.
|
2022-11-07 08:10:25 +01:00
|
|
|
let _ = OnUnimplementedDirective::of_item(tcx, item.owner_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 {
|
2023-07-07 15:24:10 -03:00
|
|
|
if !tcx.is_impl_trait_in_trait(impl_item) {
|
|
|
|
report_forbidden_specialization(tcx, impl_item, parent_impl);
|
|
|
|
} else {
|
|
|
|
tcx.sess.delay_span_bug(
|
|
|
|
DUMMY_SP,
|
2023-07-25 23:17:39 +02:00
|
|
|
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,
|
|
|
|
impl_trait_ref: ty::TraitRef<'tcx>,
|
|
|
|
) {
|
|
|
|
// 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.
|
|
|
|
if impl_trait_ref.references_error() {
|
|
|
|
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
|
|
|
|
match tcx.impl_polarity(impl_id) {
|
|
|
|
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);
|
2020-09-19 13:51:59 -07:00
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
first_item_span,
|
|
|
|
E0749,
|
|
|
|
"negative impls cannot have any items"
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
|
2021-01-22 18:15:55 +01:00
|
|
|
|
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-02-12 18:49:54 +00:00
|
|
|
tcx.sess.delay_span_bug(tcx.def_span(impl_item), "missing associated item in trait");
|
2021-01-22 18:15:55 +01:00
|
|
|
continue;
|
|
|
|
};
|
2023-02-12 18:49:54 +00:00
|
|
|
match ty_impl_item.kind {
|
|
|
|
ty::AssocKind::Const => {
|
2023-07-14 17:38:45 +00:00
|
|
|
tcx.ensure().compare_impl_const((
|
2023-02-12 18:49:54 +00:00
|
|
|
impl_item.expect_local(),
|
2022-09-30 18:53:32 +01:00
|
|
|
ty_impl_item.trait_item_def_id.unwrap(),
|
2022-09-30 17:47:39 +01:00
|
|
|
));
|
2021-11-18 21:35:42 +00:00
|
|
|
}
|
2023-02-12 18:49:54 +00:00
|
|
|
ty::AssocKind::Fn => {
|
2023-02-06 08:57:34 +00:00
|
|
|
compare_impl_method(tcx, ty_impl_item, ty_trait_item, impl_trait_ref);
|
2021-11-18 21:35:42 +00:00
|
|
|
}
|
2023-02-12 18:49:54 +00:00
|
|
|
ty::AssocKind::Type => {
|
2023-02-06 08:57:34 +00:00
|
|
|
compare_impl_ty(tcx, ty_impl_item, ty_trait_item, impl_trait_ref);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
2021-11-18 21:35:42 +00:00
|
|
|
for &trait_item_id in tcx.associated_item_def_ids(impl_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
|
|
|
|
2023-06-01 06:14:06 +00:00
|
|
|
if !is_implemented && tcx.defaultness(impl_id).is_final() {
|
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 {
|
2023-02-12 18:49:54 +00:00
|
|
|
let full_impl_span =
|
|
|
|
tcx.hir().span_with_body(tcx.hir().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
|
|
|
)
|
|
|
|
};
|
|
|
|
tcx.sess
|
|
|
|
.struct_span_err(tcx.def_span(def_id), msg)
|
|
|
|
.note(format!(
|
|
|
|
"specialization behaves in inconsistent and \
|
2023-09-13 16:04:42 +00:00
|
|
|
surprising ways with {feature}, \
|
2023-02-28 02:03:26 +00:00
|
|
|
and for now is disallowed"
|
|
|
|
))
|
|
|
|
.emit();
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2021-01-22 08:22:15 +01:00
|
|
|
if !missing_items.is_empty() {
|
2023-02-12 18:49:54 +00:00
|
|
|
let full_impl_span =
|
|
|
|
tcx.hir().span_with_body(tcx.hir().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
|
2022-05-02 09:31:56 +02:00
|
|
|
.get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of)
|
2021-12-21 18:40:50 +03:00
|
|
|
.map(|attr| attr.span);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub 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() {
|
|
|
|
struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
|
|
|
|
return;
|
|
|
|
}
|
2023-07-11 22:35:29 +01:00
|
|
|
let e = fields[FieldIdx::from_u32(0)].ty(tcx, args);
|
|
|
|
if !fields.iter().all(|f| f.ty(tcx, args) == e) {
|
2022-04-15 15:56:32 +09:00
|
|
|
struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
|
|
|
|
.span_label(sp, "SIMD elements must have the same type")
|
|
|
|
.emit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let len = if let ty::Array(_ty, c) = e.kind() {
|
2023-02-14 08:51:19 +00:00
|
|
|
c.try_eval_target_usize(tcx, tcx.param_env(def.did()))
|
2022-04-15 15:56:32 +09:00
|
|
|
} else {
|
|
|
|
Some(fields.len() as u64)
|
|
|
|
};
|
|
|
|
if let Some(len) = len {
|
|
|
|
if len == 0 {
|
2020-09-19 13:51:59 -07:00
|
|
|
struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
|
|
|
|
return;
|
2022-04-15 15:56:32 +09:00
|
|
|
} else if len > MAX_SIMD_LANES {
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
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
|
|
|
|
// No: char, "fat" pointers, compound types
|
|
|
|
match e.kind() {
|
|
|
|
ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
|
|
|
|
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
|
|
|
|
ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
|
|
|
|
ty::Array(t, _clen)
|
|
|
|
if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) =>
|
|
|
|
{ /* struct([f32; 4]) is ok */ }
|
|
|
|
_ => {
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
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() {
|
2022-05-02 09:31:56 +02:00
|
|
|
for attr in tcx.get_attrs(def.did(), sym::repr) {
|
|
|
|
for r in attr::parse_repr_attr(&tcx.sess, attr) {
|
2022-02-26 07:43:47 -03:00
|
|
|
if let attr::ReprPacked(pack) = r
|
2022-05-02 09:31:56 +02:00
|
|
|
&& let Some(repr_pack) = repr.pack
|
|
|
|
&& pack as u64 != repr_pack.bytes()
|
|
|
|
{
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
sp,
|
|
|
|
E0634,
|
|
|
|
"type has conflicting packed representation hints"
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if repr.align.is_some() {
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
sp,
|
|
|
|
E0587,
|
|
|
|
"type has conflicting packed and align representation hints"
|
|
|
|
)
|
|
|
|
.emit();
|
|
|
|
} else {
|
2022-03-05 07:28:41 +11:00
|
|
|
if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) {
|
2020-09-19 13:51:59 -07:00
|
|
|
let mut err = struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
sp,
|
|
|
|
E0588,
|
|
|
|
"packed type cannot transitively contain a `#[repr(align)]` type"
|
|
|
|
);
|
|
|
|
|
|
|
|
err.span_note(
|
|
|
|
tcx.def_span(def_spans[0].0),
|
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!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),
|
2020-09-19 13:51:59 -07: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,
|
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
|
|
|
if first {
|
2020-09-19 13:51:59 -07:00
|
|
|
format!(
|
|
|
|
"`{}` contains a field of type `{}`",
|
2023-07-11 22:35:29 +01:00
|
|
|
tcx.type_of(def.did()).instantiate_identity(),
|
2020-09-19 13:51:59 -07:00
|
|
|
ident
|
|
|
|
)
|
|
|
|
} else {
|
2022-04-15 15:56:32 +09:00
|
|
|
format!("...which contains a field of type `{ident}`")
|
2020-09-19 13:51:59 -07:00
|
|
|
},
|
|
|
|
);
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if adt.is_union() && !tcx.features().transparent_unions {
|
|
|
|
feature_err(
|
|
|
|
&tcx.sess.parse_sess,
|
|
|
|
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));
|
2020-09-19 13:51:59 -07:00
|
|
|
let param_env = tcx.param_env(field.did);
|
|
|
|
let layout = tcx.layout_of(param_env.and(ty));
|
|
|
|
// We are currently checking the type this field came from, so it must be local
|
|
|
|
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),
|
|
|
|
ty::Adt(def, subst) => {
|
|
|
|
if !def.did().is_local() {
|
|
|
|
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(),
|
|
|
|
subst,
|
|
|
|
non_exhaustive,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
def.all_fields()
|
|
|
|
.map(|field| field.ty(tcx, subst))
|
|
|
|
.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 {
|
|
|
|
tcx.struct_span_lint_hir(
|
|
|
|
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
|
|
|
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
|
|
|
|
span,
|
|
|
|
"zero-sized fields in `repr(transparent)` cannot \
|
|
|
|
contain external non-exhaustive types",
|
|
|
|
|lint| {
|
|
|
|
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."
|
|
|
|
))
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} 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() {
|
2023-03-13 18:54:05 +00:00
|
|
|
if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() {
|
2020-09-19 13:51:59 -07:00
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
attr.span,
|
|
|
|
E0084,
|
|
|
|
"unsupported representation for zero-variant enum"
|
|
|
|
)
|
2022-10-30 18:31:03 +00:00
|
|
|
.span_label(tcx.def_span(def_id), "zero-variant enum")
|
2020-09-19 13:51:59 -07:00
|
|
|
.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
if !tcx.features().repr128 {
|
|
|
|
feature_err(
|
|
|
|
&tcx.sess.parse_sess,
|
|
|
|
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 {
|
|
|
|
tcx.ensure().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));
|
|
|
|
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) {
|
2022-10-30 18:31:03 +00:00
|
|
|
let mut err = struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
tcx.def_span(def_id),
|
|
|
|
E0732,
|
|
|
|
"`#[repr(inttype)]` must be specified"
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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`
|
2022-10-30 18:31:03 +00:00
|
|
|
let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
|
|
|
|
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) =
|
|
|
|
tcx.hir().get_by_def_id(discr_def_id.expect_local())
|
|
|
|
&& 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;
|
2022-08-07 17:24:25 +02:00
|
|
|
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
|
|
|
|
|
|
|
|
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(|| {
|
|
|
|
let mut ret = struct_span_err!(
|
|
|
|
tcx.sess,
|
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
|
|
|
|
2022-08-07 17:24:25 +02:00
|
|
|
if let Some(mut e) = error {
|
|
|
|
e.emit();
|
|
|
|
}
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
}
|
2021-07-15 21:25:11 +02:00
|
|
|
}
|
|
|
|
|
2020-09-19 13:51:59 -07:00
|
|
|
pub(super) fn check_type_params_are_used<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
generics: &ty::Generics,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
) {
|
|
|
|
debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
|
|
|
|
|
|
|
|
assert_eq!(generics.parent, None);
|
|
|
|
|
|
|
|
if generics.own_counts().types == 0 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut params_used = BitSet::new_empty(generics.params.len());
|
|
|
|
|
|
|
|
if ty.references_error() {
|
|
|
|
// If there is already another error, do not emit
|
|
|
|
// an error for not using a type parameter.
|
2022-01-22 18:49:12 -06:00
|
|
|
assert!(tcx.sess.has_errors().is_some());
|
2020-09-19 13:51:59 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for param in &generics.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);
|
|
|
|
struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,)
|
|
|
|
.span_label(span, "unused type parameter")
|
|
|
|
.emit();
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-26 20:53:51 +02:00
|
|
|
pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
2022-04-29 12:22:40 -04:00
|
|
|
let module = tcx.hir_module_items(module_def_id);
|
|
|
|
for id in module.items() {
|
2022-04-29 13:09:03 -04:00
|
|
|
check_item_type(tcx, id);
|
2022-04-29 12:22:40 -04:00
|
|
|
}
|
2023-04-26 20:53:05 +02:00
|
|
|
if module_def_id == LocalModDefId::CRATE_DEF_ID {
|
2023-02-19 18:44:08 +00:00
|
|
|
super::entry::check_for_entry_fn(tcx);
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2022-01-22 18:49:12 -06:00
|
|
|
fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {
|
2020-09-19 13:51:59 -07:00
|
|
|
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
|
|
|
|
.span_label(span, "recursive `async fn`")
|
|
|
|
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
|
2021-02-09 18:43:39 +05:30
|
|
|
.note(
|
|
|
|
"consider using the `async_recursion` crate: https://crates.io/crates/async_recursion",
|
|
|
|
)
|
2022-01-22 18:49:12 -06:00
|
|
|
.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.
|
2023-01-08 00:29:30 +00:00
|
|
|
fn opaque_type_cycle_error(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
opaque_def_id: LocalDefId,
|
|
|
|
span: Span,
|
|
|
|
) -> ErrorGuaranteed {
|
2020-09-19 13:51:59 -07:00
|
|
|
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
|
|
|
|
|
|
|
|
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>,
|
|
|
|
}
|
2023-02-22 02:18:40 +00:00
|
|
|
impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector {
|
2020-11-05 17:30:39 +01:00
|
|
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
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);
|
2023-01-17 23:17:13 -08:00
|
|
|
ControlFlow::Continue(())
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2023-01-08 00:29:30 +00:00
|
|
|
ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
|
|
|
|
self.closures.push(def_id);
|
|
|
|
t.super_visit_with(self)
|
|
|
|
}
|
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));
|
|
|
|
}
|
|
|
|
// Label any generator locals that capture the opaque
|
2023-01-28 12:56:04 +00:00
|
|
|
if let DefKind::Generator = tcx.def_kind(closure_def_id)
|
2023-05-13 13:19:01 +01:00
|
|
|
&& let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id)
|
2023-01-28 22:45:52 +00:00
|
|
|
{
|
|
|
|
for interior_ty in &generator_layout.field_tys {
|
|
|
|
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
|
|
|
|
|
|
|
pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|
|
|
debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator));
|
|
|
|
|
|
|
|
let typeck = tcx.typeck(def_id);
|
|
|
|
let param_env = tcx.param_env(def_id);
|
|
|
|
|
|
|
|
let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id];
|
|
|
|
debug!(?generator_interior_predicates);
|
|
|
|
|
|
|
|
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()
|
|
|
|
// Bind opaque types to `def_id` as they should have been checked by borrowck.
|
|
|
|
.with_opaque_type_inference(DefiningAnchor::Bind(def_id))
|
|
|
|
.build();
|
|
|
|
|
2023-05-31 01:21:38 +00:00
|
|
|
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
|
2022-10-01 15:57:22 +02:00
|
|
|
for (predicate, cause) in generator_interior_predicates {
|
|
|
|
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
|
|
|
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
|
|
|
}
|
2023-09-23 04:03:24 +00:00
|
|
|
|
|
|
|
if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
|
|
|
|
&& let Some(generator) = tcx.mir_generator_witnesses(def_id)
|
|
|
|
{
|
|
|
|
for field_ty in generator.field_tys.iter() {
|
|
|
|
fulfillment_cx.register_bound(
|
|
|
|
&infcx,
|
|
|
|
param_env,
|
|
|
|
field_ty.ty,
|
|
|
|
tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
|
|
|
|
ObligationCause::new(
|
|
|
|
field_ty.source_info.span,
|
|
|
|
def_id,
|
|
|
|
ObligationCauseCode::SizedGeneratorInterior(def_id),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-01 15:57:22 +02:00
|
|
|
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
|
|
|
debug!(?errors);
|
|
|
|
if !errors.is_empty() {
|
2023-08-14 13:09:53 +00:00
|
|
|
infcx.err_ctxt().report_fulfillment_errors(errors);
|
2022-10-01 15:57:22 +02:00
|
|
|
}
|
|
|
|
}
|