2022-07-07 16:14:27 +02:00
|
|
|
use crate::check::intrinsicck::InlineAsmCtxt;
|
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
|
|
|
use crate::errors::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;
|
2022-03-24 02:03:04 +00:00
|
|
|
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
|
2020-09-19 13:51:59 -07:00
|
|
|
use rustc_hir as hir;
|
2022-10-30 18:31:03 +00:00
|
|
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
2021-04-26 01:09:35 +08:00
|
|
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
2021-02-12 16:50:45 +08:00
|
|
|
use rustc_hir::intravisit::Visitor;
|
2022-05-12 22:29:04 +02:00
|
|
|
use rustc_hir::{ItemKind, Node, PathSegment};
|
2022-11-14 18:20:49 +00:00
|
|
|
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
|
2022-06-27 18:46:16 +02:00
|
|
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
2022-07-02 16:37:49 +03:00
|
|
|
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
2022-10-01 15:57:22 +02:00
|
|
|
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
|
2022-07-07 16:55:41 +00:00
|
|
|
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
2021-11-03 18:03:12 -05:00
|
|
|
use rustc_middle::hir::nested_filter;
|
2022-04-27 18:14:19 +04:00
|
|
|
use rustc_middle::middle::stability::EvalResult;
|
2022-02-24 14:10:41 -05:00
|
|
|
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
2020-09-19 13:51:59 -07:00
|
|
|
use rustc_middle::ty::subst::GenericArgKind;
|
2021-04-27 15:01:37 +02:00
|
|
|
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
2022-11-23 18:15:50 -08:00
|
|
|
use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
|
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};
|
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-10-01 15:57:22 +02:00
|
|
|
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
|
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 {
|
2020-09-19 13:51:59 -07:00
|
|
|
let item_type = tcx.type_of(item_def_id);
|
|
|
|
if let ty::Adt(def, substs) = item_type.kind() {
|
|
|
|
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
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Fallback case: allow `ManuallyDrop` and things that are `Copy`.
|
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)
|
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-01-16 15:18:14 +01:00
|
|
|
let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, substs));
|
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"),
|
|
|
|
};
|
2020-09-19 13:51:59 -07:00
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
field_span,
|
|
|
|
E0740,
|
2022-02-15 20:16:19 +01:00
|
|
|
"unions cannot contain fields that may need dropping"
|
|
|
|
)
|
|
|
|
.note(
|
|
|
|
"a type is guaranteed not to need dropping \
|
|
|
|
when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type",
|
2020-09-19 13:51:59 -07:00
|
|
|
)
|
2021-11-14 22:04:25 +11:00
|
|
|
.multipart_suggestion_verbose(
|
2022-02-15 20:16:19 +01:00
|
|
|
"when the type does not implement `Copy`, \
|
|
|
|
wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped",
|
2021-11-15 14:47:36 +11:00
|
|
|
vec![
|
2022-02-03 23:12:25 +01:00
|
|
|
(ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()),
|
2021-11-15 14:47:36 +11:00
|
|
|
(ty_span.shrink_to_hi(), ">".into()),
|
|
|
|
],
|
2021-11-14 22:04:25 +11:00
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
)
|
2020-09-19 13:51:59 -07:00
|
|
|
.emit();
|
|
|
|
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.
|
|
|
|
let ty = tcx.type_of(def_id);
|
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(_))
|
|
|
|
if {
|
|
|
|
let node = tcx.hir().get_by_def_id(def_id);
|
|
|
|
matches!(
|
|
|
|
node,
|
|
|
|
hir::Node::ForeignItem(hir::ForeignItem {
|
|
|
|
kind: hir::ForeignItemKind::Static(..),
|
|
|
|
..
|
|
|
|
})
|
|
|
|
)
|
|
|
|
} =>
|
|
|
|
{
|
|
|
|
tcx.sess
|
|
|
|
.struct_span_err(span, "extern static is too large for the current architecture")
|
|
|
|
.emit();
|
|
|
|
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) => {
|
|
|
|
tcx.sess.delay_span_bug(span, &e.to_string());
|
|
|
|
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 {
|
|
|
|
tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item");
|
|
|
|
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
|
|
|
|
2022-10-27 14:02:18 +11:00
|
|
|
let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
|
|
|
|
let span = tcx.def_span(item.owner_id.def_id);
|
2022-09-30 19:16:13 +00:00
|
|
|
|
2022-10-24 16:06:25 +00:00
|
|
|
if !tcx.features().impl_trait_projections {
|
|
|
|
check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
|
|
|
|
}
|
2022-10-27 14:02:18 +11:00
|
|
|
if tcx.type_of(item.owner_id.def_id).references_error() {
|
2020-06-28 16:46:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-10-27 14:02:18 +11:00
|
|
|
if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
|
2022-09-30 19:16:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-10-27 14:02:18 +11:00
|
|
|
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, 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 use `Self` or `T::Foo` projections that would result
|
|
|
|
/// in "inheriting lifetimes".
|
2021-01-24 00:00:00 +00:00
|
|
|
#[instrument(level = "debug", skip(tcx, span))]
|
2022-12-20 22:10:40 +01:00
|
|
|
pub(super) fn check_opaque_for_inheriting_lifetimes(
|
|
|
|
tcx: TyCtxt<'_>,
|
2020-09-19 13:51:59 -07:00
|
|
|
def_id: LocalDefId,
|
|
|
|
span: Span,
|
|
|
|
) {
|
2021-10-20 22:38:10 +02:00
|
|
|
let item = tcx.hir().expect_item(def_id);
|
2020-12-06 21:31:42 +01:00
|
|
|
debug!(?item, ?span);
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2020-12-06 21:31:42 +01:00
|
|
|
struct ProhibitOpaqueVisitor<'tcx> {
|
2021-03-13 16:05:15 +01:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2020-12-06 21:31:42 +01:00
|
|
|
opaque_identity_ty: Ty<'tcx>,
|
2022-11-14 18:20:49 +00:00
|
|
|
parent_count: u32,
|
|
|
|
references_parent_regions: bool,
|
2021-02-13 14:45:53 +08:00
|
|
|
selftys: Vec<(Span, Option<String>)>,
|
2020-12-06 21:31:42 +01:00
|
|
|
}
|
|
|
|
|
2023-02-09 19:38:07 +00:00
|
|
|
impl<'tcx> ty::visit::ir::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueVisitor<'tcx> {
|
2020-12-06 21:31:42 +01:00
|
|
|
type BreakTy = Ty<'tcx>;
|
|
|
|
|
|
|
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
2022-10-23 20:38:34 +00:00
|
|
|
debug!(?t, "root_visit_ty");
|
2020-12-06 21:31:42 +01:00
|
|
|
if t == self.opaque_identity_ty {
|
2023-01-17 23:17:13 -08:00
|
|
|
ControlFlow::Continue(())
|
2020-12-06 21:31:42 +01:00
|
|
|
} else {
|
2022-11-14 18:20:49 +00:00
|
|
|
t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
2022-10-23 20:38:34 +00:00
|
|
|
tcx: self.tcx,
|
2022-11-14 18:20:49 +00:00
|
|
|
op: |region| {
|
|
|
|
if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *region
|
|
|
|
&& index < self.parent_count
|
|
|
|
{
|
|
|
|
self.references_parent_regions= true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
if self.references_parent_regions {
|
|
|
|
ControlFlow::Break(t)
|
|
|
|
} else {
|
2023-01-17 23:17:13 -08:00
|
|
|
ControlFlow::Continue(())
|
2022-11-14 18:20:49 +00:00
|
|
|
}
|
2020-12-06 21:31:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-13 21:45:08 -04:00
|
|
|
impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
|
2021-11-03 18:03:12 -05:00
|
|
|
type NestedFilter = nested_filter::OnlyBodies;
|
2021-02-13 14:45:53 +08:00
|
|
|
|
2021-11-03 18:03:12 -05:00
|
|
|
fn nested_visit_map(&mut self) -> Self::Map {
|
|
|
|
self.tcx.hir()
|
2021-02-13 14:45:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
|
|
|
|
match arg.kind {
|
|
|
|
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
|
2022-09-16 11:45:33 +10:00
|
|
|
[PathSegment { res: Res::SelfTyParam { .. }, .. }] => {
|
|
|
|
let impl_ty_name = None;
|
|
|
|
self.selftys.push((path.span, impl_ty_name));
|
|
|
|
}
|
|
|
|
[PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => {
|
|
|
|
let impl_ty_name = Some(self.tcx.def_path_str(*def_id));
|
2021-02-13 14:45:53 +08:00
|
|
|
self.selftys.push((path.span, impl_ty_name));
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
hir::intravisit::walk_ty(self, arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-17 16:00:04 +00:00
|
|
|
if let ItemKind::OpaqueTy(hir::OpaqueTy {
|
|
|
|
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
2022-10-23 20:38:34 +00:00
|
|
|
in_trait,
|
2022-02-17 16:00:04 +00:00
|
|
|
..
|
|
|
|
}) = item.kind
|
2020-09-19 13:51:59 -07:00
|
|
|
{
|
2022-10-23 20:38:34 +00:00
|
|
|
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
|
|
|
let opaque_identity_ty = if in_trait {
|
|
|
|
tcx.mk_projection(def_id.to_def_id(), substs)
|
|
|
|
} else {
|
|
|
|
tcx.mk_opaque(def_id.to_def_id(), substs)
|
|
|
|
};
|
2020-09-19 13:51:59 -07:00
|
|
|
let mut visitor = ProhibitOpaqueVisitor {
|
2022-10-23 20:38:34 +00:00
|
|
|
opaque_identity_ty,
|
2022-11-14 18:20:49 +00:00
|
|
|
parent_count: tcx.generics_of(def_id).parent_count as u32,
|
|
|
|
references_parent_regions: false,
|
2021-02-13 14:45:53 +08:00
|
|
|
tcx,
|
|
|
|
selftys: vec![],
|
2020-09-19 13:51:59 -07:00
|
|
|
};
|
|
|
|
let prohibit_opaque = tcx
|
2020-06-27 21:36:35 +01:00
|
|
|
.explicit_item_bounds(def_id)
|
2020-09-19 13:51:59 -07:00
|
|
|
.iter()
|
2020-11-05 19:17:30 +01:00
|
|
|
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2020-11-05 19:17:30 +01:00
|
|
|
if let Some(ty) = prohibit_opaque.break_value() {
|
2021-02-12 16:50:45 +08:00
|
|
|
visitor.visit_item(&item);
|
2022-02-17 16:00:04 +00:00
|
|
|
let is_async = match item.kind {
|
|
|
|
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
|
|
|
|
matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..))
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2020-09-19 13:51:59 -07:00
|
|
|
|
2022-10-24 16:06:25 +00:00
|
|
|
let mut err = feature_err(
|
|
|
|
&tcx.sess.parse_sess,
|
|
|
|
sym::impl_trait_projections,
|
2020-09-19 13:51:59 -07:00
|
|
|
span,
|
2022-10-24 16:06:25 +00:00
|
|
|
&format!(
|
|
|
|
"`{}` return type cannot contain a projection or `Self` that references \
|
|
|
|
lifetimes from a parent scope",
|
|
|
|
if is_async { "async fn" } else { "impl Trait" },
|
|
|
|
),
|
2020-09-19 13:51:59 -07:00
|
|
|
);
|
2021-02-13 14:45:53 +08:00
|
|
|
for (span, name) in visitor.selftys {
|
2021-02-12 16:50:45 +08:00
|
|
|
err.span_suggestion(
|
|
|
|
span,
|
|
|
|
"consider spelling out the type instead",
|
2021-02-13 14:45:53 +08:00
|
|
|
name.unwrap_or_else(|| format!("{:?}", ty)),
|
2021-02-12 16:50:45 +08:00
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks that an opaque type does not contain cycles.
|
|
|
|
pub(super) fn check_opaque_for_cycles<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
def_id: LocalDefId,
|
|
|
|
substs: SubstsRef<'tcx>,
|
|
|
|
span: Span,
|
|
|
|
origin: &hir::OpaqueTyOrigin,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> Result<(), ErrorGuaranteed> {
|
2021-07-14 12:31:58 -03:00
|
|
|
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs).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,
|
|
|
|
substs: SubstsRef<'tcx>,
|
|
|
|
span: Span,
|
|
|
|
origin: &hir::OpaqueTyOrigin,
|
|
|
|
) {
|
2021-12-01 16:34:40 +00:00
|
|
|
let defining_use_anchor = match *origin {
|
|
|
|
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
|
|
|
hir::OpaqueTyOrigin::TyAlias => def_id,
|
|
|
|
};
|
|
|
|
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);
|
|
|
|
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
2022-09-19 22:03:59 -05:00
|
|
|
|
2022-10-13 13:49:38 +03:00
|
|
|
// `ReErased` regions appear in the "parent_substs" of closures/generators.
|
|
|
|
// We're ignoring them here and replacing them with fresh region variables.
|
|
|
|
// See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs.
|
|
|
|
//
|
|
|
|
// FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
|
|
|
|
// here rather than using ReErased.
|
|
|
|
let hidden_ty = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
|
|
|
|
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);
|
2022-07-02 16:37:49 +03:00
|
|
|
tcx.sess.delay_span_bug(
|
|
|
|
span,
|
2023-01-06 00:53:31 +00:00
|
|
|
&format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
|
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.
|
2022-11-09 10:49:28 +00:00
|
|
|
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into()));
|
|
|
|
ocx.register_obligation(Obligation::new(tcx, misc_cause, 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() {
|
2022-11-02 01:34:17 +00:00
|
|
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None);
|
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.
|
|
|
|
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
|
|
|
// Can have different predicates to their defining use
|
|
|
|
hir::OpaqueTyOrigin::TyAlias => {
|
|
|
|
let outlives_environment = OutlivesEnvironment::new(param_env);
|
2022-12-26 22:41:49 +00:00
|
|
|
let _ = infcx.err_ctxt().check_region_obligations_and_report_errors(
|
2022-07-02 16:37:49 +03:00
|
|
|
defining_use_anchor,
|
|
|
|
&outlives_environment,
|
|
|
|
);
|
|
|
|
}
|
2022-09-19 22:03:59 -05:00
|
|
|
}
|
2022-07-02 16:37:49 +03:00
|
|
|
// Clean up after ourselves
|
2023-01-09 18:14:28 +00:00
|
|
|
let _ = infcx.take_opaque_types();
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2022-11-23 18:15:50 -08:00
|
|
|
fn is_enum_of_nonnullable_ptr<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
adt_def: AdtDef<'tcx>,
|
|
|
|
substs: SubstsRef<'tcx>,
|
|
|
|
) -> bool {
|
|
|
|
if adt_def.repr().inhibit_enum_layout_opt() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let [var_one, var_two] = &adt_def.variants().raw[..] else {
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else {
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
if match tcx.type_of(def_id).kind() {
|
|
|
|
ty::RawPtr(_) => false,
|
2022-11-23 18:15:50 -08:00
|
|
|
ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
|
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,
|
|
|
|
tcx.def_path_str(id.owner_id.to_def_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
|
|
|
|
DefKind::Impl => {
|
|
|
|
let it = tcx.hir().item(id);
|
2023-01-09 16:30:40 +00:00
|
|
|
let hir::ItemKind::Impl(impl_) = it.kind else { return };
|
2022-10-27 14:02:18 +11:00
|
|
|
debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
|
2023-01-10 14:57:22 -07:00
|
|
|
if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
|
2020-11-22 17:46:21 -05:00
|
|
|
check_impl_items_against_trait(
|
|
|
|
tcx,
|
|
|
|
it.span,
|
2022-10-27 14:02:18 +11:00
|
|
|
it.owner_id.def_id,
|
2023-01-11 11:32:33 -07:00
|
|
|
impl_trait_ref.subst_identity(),
|
2020-11-22 17:46:21 -05:00
|
|
|
&impl_.items,
|
|
|
|
);
|
2022-03-06 19:51:30 -08:00
|
|
|
check_on_unimplemented(tcx, it);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::Trait => {
|
|
|
|
let it = tcx.hir().item(id);
|
2023-01-09 16:30:40 +00:00
|
|
|
let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else {
|
2022-04-29 13:09:03 -04:00
|
|
|
return;
|
|
|
|
};
|
2022-03-06 19:51:30 -08:00
|
|
|
check_on_unimplemented(tcx, it);
|
2020-09-19 13:51:59 -07:00
|
|
|
|
|
|
|
for item in items.iter() {
|
|
|
|
let item = tcx.hir().trait_item(item.id);
|
2023-01-09 16:30:40 +00:00
|
|
|
match &item.kind {
|
|
|
|
hir::TraitItemKind::Fn(sig, _) => {
|
2020-06-27 21:36:35 +01:00
|
|
|
let abi = sig.header.abi;
|
|
|
|
fn_maybe_err(tcx, item.ident.span, abi);
|
|
|
|
}
|
2021-12-11 02:20:41 +00:00
|
|
|
hir::TraitItemKind::Type(.., Some(default)) => {
|
2022-10-27 14:02:18 +11:00
|
|
|
let assoc_item = tcx.associated_item(item.owner_id);
|
2020-06-27 21:36:35 +01:00
|
|
|
let trait_substs =
|
2022-10-27 14:02:18 +11:00
|
|
|
InternalSubsts::identity_for_item(tcx, it.owner_id.to_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,
|
2021-12-11 02:20:41 +00:00
|
|
|
default.span,
|
2022-12-13 11:18:58 +00:00
|
|
|
tcx.mk_trait_ref(it.owner_id.to_def_id(), trait_substs),
|
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 => {
|
2022-09-30 19:16:13 +00:00
|
|
|
check_opaque(tcx, id);
|
|
|
|
}
|
|
|
|
DefKind::ImplTraitPlaceholder => {
|
2022-10-27 14:02:18 +11:00
|
|
|
let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id());
|
2022-09-30 19:16:13 +00:00
|
|
|
// Only check the validity of this opaque type if the function has a default body
|
|
|
|
if let hir::Node::TraitItem(hir::TraitItem {
|
|
|
|
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
|
|
|
|
..
|
|
|
|
}) = tcx.hir().get_by_def_id(parent.expect_local())
|
|
|
|
{
|
|
|
|
check_opaque(tcx, id);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2022-04-29 13:09:03 -04:00
|
|
|
DefKind::TyAlias => {
|
2022-10-27 14:02:18 +11:00
|
|
|
let pty_ty = tcx.type_of(id.owner_id);
|
|
|
|
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",
|
|
|
|
)
|
|
|
|
.span_label(item.span, &format!("can't have {kinds} parameters"))
|
|
|
|
.help(
|
|
|
|
// FIXME: once we start storing spans for type arguments, turn this
|
|
|
|
// into a suggestion.
|
|
|
|
&format!(
|
|
|
|
"replace the {} parameters with concrete {}{}",
|
|
|
|
kinds,
|
|
|
|
kinds_pl,
|
|
|
|
egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-06 19:51:30 -08:00
|
|
|
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
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,
|
|
|
|
trait_item: &ty::AssocItem,
|
|
|
|
impl_id: DefId,
|
2021-11-18 21:35:42 +00:00
|
|
|
impl_item: &hir::ImplItemRef,
|
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 => {
|
|
|
|
if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
|
|
|
|
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 {
|
|
|
|
report_forbidden_specialization(tcx, impl_item, parent_impl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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>,
|
|
|
|
full_impl_span: Span,
|
|
|
|
impl_id: LocalDefId,
|
|
|
|
impl_trait_ref: ty::TraitRef<'tcx>,
|
2021-07-15 22:19:39 +02:00
|
|
|
impl_item_refs: &[hir::ImplItemRef],
|
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.
|
|
|
|
if impl_trait_ref.references_error() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
let first_item_span = tcx.hir().impl_item(first_item_ref.id).span;
|
|
|
|
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
|
|
|
|
2021-11-18 21:35:42 +00:00
|
|
|
for impl_item in impl_item_refs {
|
2022-10-27 14:02:18 +11:00
|
|
|
let ty_impl_item = tcx.associated_item(impl_item.id.owner_id);
|
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`.
|
|
|
|
tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
|
2021-01-22 18:15:55 +01:00
|
|
|
continue;
|
|
|
|
};
|
2022-01-07 14:16:56 -08:00
|
|
|
let impl_item_full = tcx.hir().impl_item(impl_item.id);
|
|
|
|
match impl_item_full.kind {
|
|
|
|
hir::ImplItemKind::Const(..) => {
|
2022-12-24 21:12:38 +00:00
|
|
|
let _ = tcx.compare_impl_const((
|
2022-10-27 14:02:18 +11:00
|
|
|
impl_item.id.owner_id.def_id,
|
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
|
|
|
}
|
2022-01-07 14:16:56 -08:00
|
|
|
hir::ImplItemKind::Fn(..) => {
|
2021-11-18 21:35:42 +00:00
|
|
|
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
|
|
|
compare_impl_method(
|
|
|
|
tcx,
|
|
|
|
&ty_impl_item,
|
|
|
|
&ty_trait_item,
|
|
|
|
impl_trait_ref,
|
|
|
|
opt_trait_span,
|
|
|
|
);
|
|
|
|
}
|
2022-10-09 07:09:57 +00:00
|
|
|
hir::ImplItemKind::Type(impl_ty) => {
|
2021-11-18 21:35:42 +00:00
|
|
|
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
2022-12-24 21:12:38 +00:00
|
|
|
compare_impl_ty(
|
2021-11-18 21:35:42 +00:00
|
|
|
tcx,
|
|
|
|
&ty_impl_item,
|
2022-01-07 14:16:56 -08:00
|
|
|
impl_ty.span,
|
2021-11-18 21:35:42 +00:00
|
|
|
&ty_trait_item,
|
|
|
|
impl_trait_ref,
|
|
|
|
opt_trait_span,
|
|
|
|
);
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-18 21:35:42 +00:00
|
|
|
|
|
|
|
check_specialization_validity(
|
|
|
|
tcx,
|
|
|
|
trait_def,
|
|
|
|
&ty_trait_item,
|
|
|
|
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) {
|
2020-09-19 13:51:59 -07:00
|
|
|
let is_implemented = ancestors
|
2021-11-18 21:35:42 +00:00
|
|
|
.leaf_def(tcx, trait_item_id)
|
2022-03-12 19:36:11 +01:00
|
|
|
.map_or(false, |node_item| node_item.item.defaultness(tcx).has_value());
|
2020-09-19 13:51:59 -07:00
|
|
|
|
|
|
|
if !is_implemented && tcx.impl_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
|
|
|
|
let is_implemented_here = ancestors
|
|
|
|
.leaf_def(tcx, trait_item_id)
|
|
|
|
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
|
|
|
|
|
|
|
|
if !is_implemented_here {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
|
|
|
|
2021-01-22 08:22:15 +01:00
|
|
|
if !missing_items.is_empty() {
|
2022-07-04 17:23:24 +09:00
|
|
|
missing_items_err(tcx, tcx.def_span(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) {
|
|
|
|
let t = tcx.type_of(def_id);
|
2022-04-15 15:56:32 +09:00
|
|
|
if let ty::Adt(def, substs) = t.kind()
|
|
|
|
&& 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;
|
|
|
|
}
|
|
|
|
let e = fields[0].ty(tcx, substs);
|
|
|
|
if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
|
|
|
|
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() {
|
|
|
|
c.try_eval_usize(tcx, tcx.param_env(def.did()))
|
|
|
|
} 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),
|
|
|
|
&format!(
|
|
|
|
"`{}` has a `#[repr(align)]` attribute",
|
|
|
|
tcx.item_name(def_spans[0].0)
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
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 `{}`",
|
2022-03-05 07:28:41 +11:00
|
|
|
tcx.type_of(def.did()),
|
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)>> {
|
|
|
|
if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() {
|
|
|
|
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 {
|
2022-04-15 15:56:32 +09:00
|
|
|
if let ty::Adt(def, _) = field.ty(tcx, substs).kind()
|
|
|
|
&& !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
|
|
|
}
|
|
|
|
|
2022-07-07 16:55:41 +00:00
|
|
|
// For each field, figure out if it's known to be a ZST and align(1), with "known"
|
|
|
|
// respecting #[non_exhaustive] attributes.
|
2020-09-19 13:51:59 -07:00
|
|
|
let field_infos = adt.all_fields().map(|field| {
|
|
|
|
let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
|
|
|
|
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();
|
2021-01-11 20:45:33 +01:00
|
|
|
let zst = layout.map_or(false, |layout| layout.is_zst());
|
|
|
|
let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
|
2022-07-07 16:55:41 +00:00
|
|
|
if !zst {
|
|
|
|
return (span, zst, align1, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_non_exhaustive<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
t: Ty<'tcx>,
|
|
|
|
) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> {
|
|
|
|
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(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
|
2020-09-19 13:51:59 -07:00
|
|
|
});
|
|
|
|
|
2022-07-07 16:55:41 +00:00
|
|
|
let non_zst_fields = field_infos
|
|
|
|
.clone()
|
|
|
|
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
|
2020-09-19 13:51:59 -07:00
|
|
|
let non_zst_count = non_zst_fields.clone().count();
|
2021-06-14 07:04:56 +09:00
|
|
|
if non_zst_count >= 2 {
|
2022-10-30 18:31:03 +00:00
|
|
|
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
|
2020-09-19 13:51:59 -07:00
|
|
|
}
|
2022-07-07 16:55:41 +00:00
|
|
|
let incompatible_zst_fields =
|
|
|
|
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
|
|
|
|
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
|
|
|
|
for (span, zst, align1, non_exhaustive) in field_infos {
|
2020-09-19 13:51:59 -07:00
|
|
|
if zst && !align1 {
|
|
|
|
struct_span_err!(
|
|
|
|
tcx.sess,
|
|
|
|
span,
|
|
|
|
E0691,
|
|
|
|
"zero-sized field in transparent {} has alignment larger than 1",
|
|
|
|
adt.descr(),
|
|
|
|
)
|
|
|
|
.span_label(span, "has alignment larger than 1")
|
|
|
|
.emit();
|
|
|
|
}
|
2022-07-07 16:55:41 +00:00
|
|
|
if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive {
|
|
|
|
tcx.struct_span_lint_hir(
|
|
|
|
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
|
|
|
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
|
|
|
|
span,
|
2022-09-16 11:01:02 +04:00
|
|
|
"zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|
2022-07-07 16:55:41 +00:00
|
|
|
|lint| {
|
|
|
|
let note = if non_exhaustive {
|
|
|
|
"is marked with `#[non_exhaustive]`"
|
|
|
|
} else {
|
|
|
|
"contains private fields"
|
|
|
|
};
|
|
|
|
let field_ty = tcx.def_path_str_with_substs(def_id, substs);
|
2022-09-16 11:01:02 +04:00
|
|
|
lint
|
2022-07-07 16:55:41 +00:00
|
|
|
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
|
|
|
|
and makes it not a breaking change to become non-zero-sized in the future."))
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
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() {
|
2022-09-06 14:16:54 +08:00
|
|
|
if let Some(attr) = tcx.get_attrs(def_id.to_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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
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
|
|
|
}
|
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-09 19:38:07 +00:00
|
|
|
impl<'tcx> ty::visit::ir::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 { "" };
|
|
|
|
err.span_label(ty_span, &format!("returning this {descr}type `{ty}`"));
|
2020-09-19 13:51:59 -07:00
|
|
|
seen.insert(ty_span);
|
|
|
|
}
|
2022-04-15 15:56:32 +09: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 {
|
|
|
|
let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
|
|
|
|
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",
|
|
|
|
tcx.def_kind(closure_def_id).descr(closure_def_id)
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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
|
|
|
|
for interior_ty in
|
|
|
|
typeck_results.generator_interior_types.as_ref().skip_binder()
|
|
|
|
{
|
|
|
|
label_match(interior_ty.ty, interior_ty.span);
|
|
|
|
}
|
|
|
|
}
|
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!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
|
|
|
|
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();
|
|
|
|
|
|
|
|
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
|
|
|
for (predicate, cause) in generator_interior_predicates {
|
|
|
|
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
|
|
|
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
|
|
|
}
|
|
|
|
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
|
|
|
debug!(?errors);
|
|
|
|
if !errors.is_empty() {
|
|
|
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None);
|
|
|
|
}
|
|
|
|
}
|