1
Fork 0

Auto merge of #136845 - matthiaskrgr:rollup-ol4np4z, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #136107 (Introduce CoercePointeeWellformed for coherence checks at typeck stage)
 - #136155 (Enable sanitizers on MSVC CI jobs)
 - #136524 (Delay bug when method confirmation cannot upcast object pick of self)
 - #136584 (Prevent generic pattern types from being used in libstd)
 - #136603 (compiler: gate `extern "{abi}"` in ast_lowering)
 - #136821 (assign marcoieni and jdno to infra-ci PRs)
 - #136825 (Update books)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-02-11 05:27:49 +00:00
commit c182ce9cbc
92 changed files with 938 additions and 502 deletions

View file

@ -9,7 +9,6 @@ bitflags = "2.4.1"
rand = { version = "0.8.4", default-features = false, optional = true }
rand_xoshiro = { version = "0.6.0", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_feature = { path = "../rustc_feature", optional = true }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_serialize = { path = "../rustc_serialize", optional = true }
@ -24,7 +23,6 @@ default = ["nightly", "randomize"]
# without depending on rustc_data_structures, rustc_macros and rustc_serialize
nightly = [
"dep:rustc_data_structures",
"dep:rustc_feature",
"dep:rustc_macros",
"dep:rustc_serialize",
"dep:rustc_span",

View file

@ -1,6 +1,5 @@
#[cfg(feature = "nightly")]
use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout};
use crate::{Primitive, Size, Variants};
use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants};
mod reg;

View file

@ -1,7 +1,6 @@
use std::fmt;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::{Span, Symbol, sym};
#[cfg(test)]
mod tests;
@ -95,14 +94,14 @@ impl Abi {
#[derive(Copy, Clone)]
pub struct AbiData {
abi: Abi,
pub abi: Abi,
/// Name of this ABI as we like it called.
name: &'static str,
pub name: &'static str,
}
#[allow(non_upper_case_globals)]
const AbiDatas: &[AbiData] = &[
pub const AbiDatas: &[AbiData] = &[
AbiData { abi: Abi::Rust, name: "Rust" },
AbiData { abi: Abi::C { unwind: false }, name: "C" },
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
@ -142,131 +141,20 @@ const AbiDatas: &[AbiData] = &[
];
#[derive(Copy, Clone, Debug)]
pub enum AbiUnsupported {
Unrecognized,
Reason { explain: &'static str },
}
pub struct AbiUnsupported {}
/// Returns the ABI with the given name (if any).
pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi).ok_or_else(|| match name {
"riscv-interrupt" => AbiUnsupported::Reason {
explain: "please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively",
},
"riscv-interrupt-u" => AbiUnsupported::Reason {
explain: "user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314",
},
"wasm" => AbiUnsupported::Reason {
explain: "non-standard wasm ABI is no longer supported",
},
_ => AbiUnsupported::Unrecognized,
})
AbiDatas
.iter()
.find(|abi_data| name == abi_data.name)
.map(|&x| x.abi)
.ok_or_else(|| AbiUnsupported {})
}
pub fn all_names() -> Vec<&'static str> {
AbiDatas.iter().map(|d| d.name).collect()
}
pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
AbiDatas
.iter()
.map(|d| d.name)
.filter(|name| is_enabled(features, span, name).is_ok())
.collect()
}
pub enum AbiDisabled {
Unstable { feature: Symbol, explain: &'static str },
Unrecognized,
}
pub fn is_enabled(
features: &rustc_feature::Features,
span: Span,
name: &str,
) -> Result<(), AbiDisabled> {
let s = is_stable(name);
if let Err(AbiDisabled::Unstable { feature, .. }) = s {
if features.enabled(feature) || span.allows_unstable(feature) {
return Ok(());
}
}
s
}
/// Returns whether the ABI is stable to use.
///
/// Note that there is a separate check determining whether the ABI is even supported
/// on the current target; see `fn is_abi_supported` in `rustc_target::spec`.
pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
match name {
// Stable
"Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind"
| "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind"
| "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" | "thiscall"
| "thiscall-unwind" => Ok(()),
"rust-intrinsic" => Err(AbiDisabled::Unstable {
feature: sym::intrinsics,
explain: "intrinsics are subject to change",
}),
"vectorcall" => Err(AbiDisabled::Unstable {
feature: sym::abi_vectorcall,
explain: "vectorcall is experimental and subject to change",
}),
"vectorcall-unwind" => Err(AbiDisabled::Unstable {
feature: sym::abi_vectorcall,
explain: "vectorcall-unwind ABI is experimental and subject to change",
}),
"rust-call" => Err(AbiDisabled::Unstable {
feature: sym::unboxed_closures,
explain: "rust-call ABI is subject to change",
}),
"rust-cold" => Err(AbiDisabled::Unstable {
feature: sym::rust_cold_cc,
explain: "rust-cold is experimental and subject to change",
}),
"ptx-kernel" => Err(AbiDisabled::Unstable {
feature: sym::abi_ptx,
explain: "PTX ABIs are experimental and subject to change",
}),
"unadjusted" => Err(AbiDisabled::Unstable {
feature: sym::abi_unadjusted,
explain: "unadjusted ABI is an implementation detail and perma-unstable",
}),
"msp430-interrupt" => Err(AbiDisabled::Unstable {
feature: sym::abi_msp430_interrupt,
explain: "msp430-interrupt ABI is experimental and subject to change",
}),
"x86-interrupt" => Err(AbiDisabled::Unstable {
feature: sym::abi_x86_interrupt,
explain: "x86-interrupt ABI is experimental and subject to change",
}),
"gpu-kernel" => Err(AbiDisabled::Unstable {
feature: sym::abi_gpu_kernel,
explain: "gpu-kernel ABI is experimental and subject to change",
}),
"avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
feature: sym::abi_avr_interrupt,
explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
}),
"riscv-interrupt-m" | "riscv-interrupt-s" => Err(AbiDisabled::Unstable {
feature: sym::abi_riscv_interrupt,
explain: "riscv-interrupt ABIs are experimental and subject to change",
}),
"C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
feature: sym::abi_c_cmse_nonsecure_call,
explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
}),
"C-cmse-nonsecure-entry" => Err(AbiDisabled::Unstable {
feature: sym::cmse_nonsecure_entry,
explain: "C-cmse-nonsecure-entry ABI is experimental and subject to change",
}),
_ => Err(AbiDisabled::Unrecognized),
}
}
impl Abi {
/// Default ABI chosen for `extern fn` declarations without an explicit ABI.
pub const FALLBACK: Abi = Abi::C { unwind: false };

View file

@ -18,7 +18,7 @@ fn lookup_cdecl() {
#[test]
fn lookup_baz() {
let abi = lookup("baz");
assert_matches!(abi, Err(AbiUnsupported::Unrecognized));
assert_matches!(abi, Err(AbiUnsupported {}));
}
#[test]

View file

@ -66,9 +66,7 @@ mod extern_abi;
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
#[cfg(feature = "nightly")]
pub use extern_abi::{
AbiDisabled, AbiUnsupported, ExternAbi, all_names, enabled_names, is_enabled, is_stable, lookup,
};
pub use extern_abi::{AbiDatas, AbiUnsupported, ExternAbi, all_names, lookup};
#[cfg(feature = "nightly")]
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
pub use layout::{LayoutCalculator, LayoutCalculatorError};

View file

@ -13,6 +13,7 @@ rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }

View file

@ -41,13 +41,13 @@ use std::iter;
use ast::visit::Visitor;
use hir::def::{DefKind, PartialRes, Res};
use hir::{BodyId, HirId};
use rustc_abi::ExternAbi;
use rustc_ast::*;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
use rustc_span::{Ident, Span};
use rustc_target::spec::abi;
use {rustc_ast as ast, rustc_hir as hir};
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
@ -398,7 +398,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
safety: hir::Safety::Safe.into(),
constness: hir::Constness::NotConst,
asyncness: hir::IsAsync::NotAsync,
abi: abi::Abi::Rust,
abi: ExternAbi::Rust,
}
}

View file

@ -1,5 +1,5 @@
use rustc_errors::DiagArgFromDisplay;
use rustc_errors::codes::*;
use rustc_errors::{Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@ -32,8 +32,6 @@ pub(crate) struct InvalidAbi {
pub abi: Symbol,
pub command: String,
#[subdiagnostic]
pub explain: Option<InvalidAbiReason>,
#[subdiagnostic]
pub suggestion: Option<InvalidAbiSuggestion>,
}
@ -45,19 +43,6 @@ pub(crate) struct TupleStructWithDefault {
pub span: Span,
}
pub(crate) struct InvalidAbiReason(pub &'static str);
impl Subdiagnostic for InvalidAbiReason {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
#[allow(rustc::untranslatable_diagnostic)]
diag.note(self.0);
}
}
#[derive(Subdiagnostic)]
#[suggestion(
ast_lowering_invalid_abi_suggestion,

View file

@ -17,9 +17,9 @@ use thin_vec::ThinVec;
use tracing::instrument;
use super::errors::{
InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound,
TupleStructWithDefault,
InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
};
use super::stability::{enabled_names, gate_unstable_abi};
use super::{
AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
ResolverAstLoweringExt,
@ -1479,11 +1479,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
pub(super) fn lower_abi(&mut self, abi: StrLit) -> ExternAbi {
rustc_abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| {
self.error_on_invalid_abi(abi, err);
pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi {
let ast::StrLit { symbol_unescaped, span, .. } = abi_str;
let extern_abi = rustc_abi::lookup(symbol_unescaped.as_str()).unwrap_or_else(|_| {
self.error_on_invalid_abi(abi_str);
ExternAbi::Rust
})
});
let sess = self.tcx.sess;
let features = self.tcx.features();
gate_unstable_abi(sess, features, span, extern_abi);
extern_abi
}
pub(super) fn lower_extern(&mut self, ext: Extern) -> ExternAbi {
@ -1494,8 +1499,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
fn error_on_invalid_abi(&self, abi: StrLit, err: rustc_abi::AbiUnsupported) {
let abi_names = rustc_abi::enabled_names(self.tcx.features(), abi.span)
fn error_on_invalid_abi(&self, abi: StrLit) {
let abi_names = enabled_names(self.tcx.features(), abi.span)
.iter()
.map(|s| Symbol::intern(s))
.collect::<Vec<_>>();
@ -1503,10 +1508,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.dcx().emit_err(InvalidAbi {
abi: abi.symbol_unescaped,
span: abi.span,
explain: match err {
rustc_abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)),
_ => None,
},
suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion {
span: abi.span,
suggestion: format!("\"{suggested_name}\""),

View file

@ -84,6 +84,7 @@ mod index;
mod item;
mod pat;
mod path;
pub mod stability;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -0,0 +1,147 @@
use std::fmt;
use rustc_abi::ExternAbi;
use rustc_feature::Features;
use rustc_session::Session;
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
rustc_abi::AbiDatas
.iter()
.filter(|data| extern_abi_enabled(features, span, data.abi).is_ok())
.map(|d| d.name)
.collect()
}
pub(crate) fn extern_abi_enabled(
features: &rustc_feature::Features,
span: Span,
abi: ExternAbi,
) -> Result<(), UnstableAbi> {
extern_abi_stability(abi).or_else(|unstable @ UnstableAbi { feature, .. }| {
if features.enabled(feature) || span.allows_unstable(feature) {
Ok(())
} else {
Err(unstable)
}
})
}
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
match extern_abi_enabled(features, span, abi) {
Ok(_) => (),
Err(unstable_abi) => {
let explain = unstable_abi.to_string();
feature_err(sess, unstable_abi.feature, span, explain).emit();
}
}
}
pub struct UnstableAbi {
abi: ExternAbi,
feature: Symbol,
explain: GateReason,
}
enum GateReason {
Experimental,
ImplDetail,
}
impl fmt::Display for UnstableAbi {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { abi, .. } = self;
let name = abi.to_string();
let name = name.trim_matches('"');
match self.explain {
GateReason::Experimental => {
write!(f, r#"the extern "{name}" ABI is experimental and subject to change"#)
}
GateReason::ImplDetail => {
write!(
f,
r#"the extern "{name}" ABI is an implementation detail and perma-unstable"#
)
}
}
}
}
pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
match abi {
// stable ABIs
ExternAbi::Rust
| ExternAbi::C { .. }
| ExternAbi::Cdecl { .. }
| ExternAbi::Stdcall { .. }
| ExternAbi::Fastcall { .. }
| ExternAbi::Thiscall { .. }
| ExternAbi::Aapcs { .. }
| ExternAbi::Win64 { .. }
| ExternAbi::SysV64 { .. }
| ExternAbi::System { .. }
| ExternAbi::EfiApi => Ok(()),
// implementation details
ExternAbi::RustIntrinsic => {
Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
}
ExternAbi::Unadjusted => {
Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
}
// experimental
ExternAbi::Vectorcall { .. } => Err(UnstableAbi {
abi,
feature: sym::abi_vectorcall,
explain: GateReason::Experimental,
}),
ExternAbi::RustCall => Err(UnstableAbi {
abi,
feature: sym::unboxed_closures,
explain: GateReason::Experimental,
}),
ExternAbi::RustCold => {
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
}
ExternAbi::GpuKernel => Err(UnstableAbi {
abi,
feature: sym::abi_gpu_kernel,
explain: GateReason::Experimental,
}),
ExternAbi::PtxKernel => {
Err(UnstableAbi { abi, feature: sym::abi_ptx, explain: GateReason::Experimental })
}
ExternAbi::Msp430Interrupt => Err(UnstableAbi {
abi,
feature: sym::abi_msp430_interrupt,
explain: GateReason::Experimental,
}),
ExternAbi::X86Interrupt => Err(UnstableAbi {
abi,
feature: sym::abi_x86_interrupt,
explain: GateReason::Experimental,
}),
ExternAbi::AvrInterrupt | ExternAbi::AvrNonBlockingInterrupt => Err(UnstableAbi {
abi,
feature: sym::abi_avr_interrupt,
explain: GateReason::Experimental,
}),
ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS => Err(UnstableAbi {
abi,
feature: sym::abi_riscv_interrupt,
explain: GateReason::Experimental,
}),
ExternAbi::CCmseNonSecureCall => Err(UnstableAbi {
abi,
feature: sym::abi_c_cmse_nonsecure_call,
explain: GateReason::Experimental,
}),
ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi {
abi,
feature: sym::cmse_nonsecure_entry,
explain: GateReason::Experimental,
}),
}
}

View file

@ -20,6 +20,7 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use itertools::{Either, Itertools};
use rustc_abi::ExternAbi;
use rustc_ast::ptr::P;
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
use rustc_ast::*;
@ -35,7 +36,6 @@ use rustc_session::lint::builtin::{
};
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
use rustc_span::{Ident, Span, kw, sym};
use rustc_target::spec::abi;
use thin_vec::thin_vec;
use crate::errors::{self, TildeConstReason};
@ -723,7 +723,7 @@ impl<'a> AstValidator<'a> {
MISSING_ABI,
id,
span,
BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK),
BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK),
)
}
}

View file

@ -1,9 +1,9 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{NodeId, PatKind, attr, token};
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue};
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
use rustc_session::Session;
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
use rustc_session::parse::{feature_err, feature_warn};
use rustc_span::source_map::Spanned;
use rustc_span::{Span, Symbol, sym};
use thin_vec::ThinVec;
@ -72,35 +72,6 @@ struct PostExpansionVisitor<'a> {
}
impl<'a> PostExpansionVisitor<'a> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn check_abi(&self, abi: ast::StrLit) {
let ast::StrLit { symbol_unescaped, span, .. } = abi;
match rustc_abi::is_enabled(self.features, span, symbol_unescaped.as_str()) {
Ok(()) => (),
Err(rustc_abi::AbiDisabled::Unstable { feature, explain }) => {
feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit();
}
Err(rustc_abi::AbiDisabled::Unrecognized) => {
if self.sess.opts.pretty.is_none_or(|ppm| ppm.needs_hir()) {
self.sess.dcx().span_delayed_bug(
span,
format!(
"unrecognized ABI not caught in lowering: {}",
symbol_unescaped.as_str()
),
);
}
}
}
}
fn check_extern(&self, ext: ast::Extern) {
if let ast::Extern::Explicit(abi, _) = ext {
self.check_abi(abi);
}
}
/// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
fn check_impl_trait(&self, ty: &ast::Ty, in_associated_ty: bool) {
struct ImplTraitVisitor<'a> {
@ -223,12 +194,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_item(&mut self, i: &'a ast::Item) {
match &i.kind {
ast::ItemKind::ForeignMod(foreign_module) => {
if let Some(abi) = foreign_module.abi {
self.check_abi(abi);
}
ast::ItemKind::ForeignMod(_foreign_module) => {
// handled during lowering
}
ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
for attr in attr::filter_by_name(&i.attrs, sym::repr) {
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
@ -315,7 +283,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
match &ty.kind {
ast::TyKind::BareFn(bare_fn_ty) => {
// Function pointers cannot be `const`
self.check_extern(bare_fn_ty.ext);
self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
}
ast::TyKind::Never => {
@ -418,9 +385,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let Some(header) = fn_kind.header() {
if let Some(_header) = fn_kind.header() {
// Stability of const fn methods are covered in `visit_assoc_item` below.
self.check_extern(header.ext);
}
if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {

View file

@ -3,11 +3,11 @@ use ast::ptr::P;
use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::visit::BoundKind;
use rustc_ast::{
self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem,
self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem,
TraitBoundModifiers, VariantData, WherePredicate,
};
use rustc_attr_parsing as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_errors::E0802;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_macros::Diagnostic;
use rustc_span::{Ident, Span, Symbol, sym};
@ -32,15 +32,6 @@ pub(crate) fn expand_deriving_coerce_pointee(
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
{
let is_transparent = aitem.attrs.iter().any(|attr| {
attr::find_repr_attrs(cx.sess, attr)
.into_iter()
.any(|r| matches!(r, attr::ReprTransparent))
});
if !is_transparent {
cx.dcx().emit_err(RequireTransparent { span });
return;
}
if !matches!(
struct_data,
VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
@ -88,8 +79,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
} else {
let mut pointees = type_params
.iter()
.filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span)))
.fuse();
.filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span)));
match (pointees.next(), pointees.next()) {
(Some((idx, _span)), None) => idx,
(None, _) => {
@ -110,6 +100,52 @@ pub(crate) fn expand_deriving_coerce_pointee(
// Declare helper function that adds implementation blocks.
// FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls
let attrs = thin_vec![cx.attr_word(sym::automatically_derived, span),];
// # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`.
{
let trait_path =
cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]);
let trait_ref = cx.trait_ref(trait_path);
push(Annotatable::Item(
cx.item(
span,
Ident::empty(),
attrs.clone(),
ast::ItemKind::Impl(Box::new(ast::Impl {
safety: ast::Safety::Default,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
generics: Generics {
params: generics
.params
.iter()
.map(|p| match &p.kind {
GenericParamKind::Lifetime => {
cx.lifetime_param(p.span(), p.ident, p.bounds.clone())
}
GenericParamKind::Type { default: _ } => {
cx.typaram(p.span(), p.ident, p.bounds.clone(), None)
}
GenericParamKind::Const { ty, kw_span: _, default: _ } => cx
.const_param(
p.span(),
p.ident,
p.bounds.clone(),
ty.clone(),
None,
),
})
.collect(),
where_clause: generics.where_clause.clone(),
span: generics.span,
},
of_trait: Some(trait_ref),
self_ty: self_type.clone(),
items: ThinVec::new(),
})),
),
));
}
let mut add_impl_block = |generics, trait_symbol, trait_args| {
let mut parts = path!(span, core::ops);
parts.push(Ident::new(trait_symbol, span));
@ -430,35 +466,35 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b>
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_transparent)]
#[diag(builtin_macros_coerce_pointee_requires_transparent, code = E0802)]
struct RequireTransparent {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_one_field)]
#[diag(builtin_macros_coerce_pointee_requires_one_field, code = E0802)]
struct RequireOneField {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_one_generic)]
#[diag(builtin_macros_coerce_pointee_requires_one_generic, code = E0802)]
struct RequireOneGeneric {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_one_pointee)]
#[diag(builtin_macros_coerce_pointee_requires_one_pointee, code = E0802)]
struct RequireOnePointee {
#[primary_span]
span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_too_many_pointees)]
#[diag(builtin_macros_coerce_pointee_too_many_pointees, code = E0802)]
struct TooManyPointees {
#[primary_span]
one: Span,
@ -467,7 +503,7 @@ struct TooManyPointees {
}
#[derive(Diagnostic)]
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)]
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)]
struct RequiresMaybeSized {
#[primary_span]
span: Span,

View file

@ -1,5 +1,6 @@
use std::str::FromStr;
use rustc_abi::ExternAbi;
use rustc_ast::attr::list_contains_name;
use rustc_ast::expand::autodiff_attrs::{
AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
@ -23,7 +24,7 @@ use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::parse::feature_err;
use rustc_session::{Session, lint};
use rustc_span::{Ident, Span, sym};
use rustc_target::spec::{SanitizerSet, abi};
use rustc_target::spec::SanitizerSet;
use tracing::debug;
use crate::errors;
@ -219,7 +220,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
if !is_closure
&& let Some(fn_sig) = fn_sig()
&& fn_sig.skip_binder().abi() != abi::Abi::Rust
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
{
struct_span_code_err!(
tcx.dcx(),

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_lowering = { path = "../rustc_ast_lowering" }
rustc_ast_passes = { path = "../rustc_ast_passes" }

View file

@ -747,7 +747,7 @@ fn print_crate_info(
}
}
CallingConventions => {
let mut calling_conventions = rustc_target::spec::abi::all_names();
let mut calling_conventions = rustc_abi::all_names();
calling_conventions.sort_unstable();
println_info!("{}", calling_conventions.join("\n"));
}

View file

@ -0,0 +1,94 @@
The target of `derive(CoercePointee)` macro has inadmissible specification for
a meaningful use.
Erroneous code examples:
The target data is not a `struct`.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
enum NotStruct<'a, T: ?Sized> {
Variant(&'a T),
}
```
The target data has a layout that is not transparent, or `repr(transparent)`
in other words.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
struct NotTransparent<'a, #[pointee] T: ?Sized> {
ptr: &'a T,
}
```
The target data has no data field.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoField<'a, #[pointee] T: ?Sized> {}
```
The target data is not generic over any data, or has no generic type parameter.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoGeneric<'a>(&'a u8);
```
The target data has multiple generic type parameters, but none is designated as
a pointee for coercion.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
a: (&'a T1, &'a T2),
}
```
The target data has multiple generic type parameters that are designated as
pointees for coercion.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct TooManyPointees<
'a,
#[pointee] A: ?Sized,
#[pointee] B: ?Sized>
((&'a A, &'a B));
```
The type parameter that is designated as a pointee is not marked `?Sized`.
```compile_fail,E0802
#![feature(coerce_pointee)]
use std::marker::CoercePointee;
#[derive(CoercePointee)]
#[repr(transparent)]
struct NoMaybeSized<'a, #[pointee] T> {
ptr: &'a T,
}
```
In summary, the `CoercePointee` macro demands the type to be a `struct` that is
generic over at least one type or over more types, one of which is marked with
`#[pointee]`, and has at least one data field and adopts a `repr(transparent)`
layout.
The only generic type or the type marked with `#[pointee]` has to be also
marked as `?Sized`.

View file

@ -545,6 +545,7 @@ E0798: 0798,
E0799: 0799,
E0800: 0800,
E0801: 0801,
E0802: 0802,
);
)
}

View file

@ -1,7 +1,8 @@
use rustc_ast::ptr::P;
use rustc_ast::util::literal;
use rustc_ast::{
self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp, attr, token,
self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp,
attr, token,
};
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
@ -138,6 +139,42 @@ impl<'a> ExtCtxt<'a> {
}
}
pub fn lifetime_param(
&self,
span: Span,
ident: Ident,
bounds: ast::GenericBounds,
) -> ast::GenericParam {
ast::GenericParam {
id: ast::DUMMY_NODE_ID,
ident: ident.with_span_pos(span),
attrs: AttrVec::new(),
bounds,
is_placeholder: false,
kind: ast::GenericParamKind::Lifetime,
colon_span: None,
}
}
pub fn const_param(
&self,
span: Span,
ident: Ident,
bounds: ast::GenericBounds,
ty: P<ast::Ty>,
default: Option<AnonConst>,
) -> ast::GenericParam {
ast::GenericParam {
id: ast::DUMMY_NODE_ID,
ident: ident.with_span_pos(span),
attrs: AttrVec::new(),
bounds,
is_placeholder: false,
kind: ast::GenericParamKind::Const { ty, kw_span: DUMMY_SP, default },
colon_span: None,
}
}
pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
}

View file

@ -513,6 +513,8 @@ declare_features! (
(incomplete, generic_const_exprs, "1.56.0", Some(76560)),
/// Allows generic parameters and where-clauses on free & associated const items.
(incomplete, generic_const_items, "1.73.0", Some(113521)),
/// Allows any generic constants being used as pattern type range ends
(incomplete, generic_pattern_types, "CURRENT_RUSTC_VERSION", Some(136574)),
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.
(unstable, global_registration, "1.80.0", Some(125119)),
/// Allows using guards in patterns.

View file

@ -370,6 +370,8 @@ language_item_table! {
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0);
ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
@ -429,9 +431,13 @@ language_item_table! {
ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None;
}
/// The requirement imposed on the generics of a lang item
pub enum GenericRequirement {
/// No restriction on the generics
None,
/// A minimum number of generics that is demanded on a lang item
Minimum(usize),
/// The number of generics must match precisely as stipulated
Exact(usize),
}

View file

@ -85,6 +85,16 @@ hir_analysis_cmse_output_stack_spill =
.note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden
hir_analysis_coerce_pointee_not_concrete_ty = `derive(CoercePointee)` is only applicable to `struct`
hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applicable to `struct`, instead of `{$kind}`
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions

View file

@ -48,6 +48,10 @@ pub(super) fn check_trait<'tcx>(
checker
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
checker.check(
lang_items.coerce_pointee_validated_trait(),
visit_implementation_of_coerce_pointee_validity,
)?;
Ok(())
}
@ -783,3 +787,32 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
.with_note(why_disqualified)
.emit())
}
fn visit_implementation_of_coerce_pointee_validity(
checker: &Checker<'_>,
) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
let span = tcx.def_span(checker.impl_def_id);
if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
}
let ty::Adt(def, _args) = self_ty.kind() else {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
};
let did = def.did();
// Now get a more precise span of the `struct`.
let span = tcx.def_span(did);
if !def.is_struct() {
return Err(tcx
.dcx()
.emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
}
if !def.repr().transparent() {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
}
if def.all_fields().next().is_none() {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
}
Ok(())
}

View file

@ -1180,6 +1180,42 @@ pub(crate) struct DispatchFromDynRepr {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_not_struct, code = E0802)]
pub(crate) struct CoercePointeeNotStruct {
#[primary_span]
pub span: Span,
pub kind: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_not_concrete_ty, code = E0802)]
pub(crate) struct CoercePointeeNotConcreteType {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_no_user_validity_assertion, code = E0802)]
pub(crate) struct CoercePointeeNoUserValidityAssertion {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_not_transparent, code = E0802)]
pub(crate) struct CoercePointeeNotTransparent {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_coerce_pointee_no_field, code = E0802)]
pub(crate) struct CoercePointeeNoField {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)]
#[help]

View file

@ -681,17 +681,23 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
// must be exactly one trait ref or we'd get an ambig error etc
let [upcast_trait_ref] = upcast_trait_refs.as_slice() else {
span_bug!(
if let &[upcast_trait_ref] = upcast_trait_refs.as_slice() {
upcast_trait_ref
} else {
self.dcx().span_delayed_bug(
self.span,
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
source_trait_ref,
target_trait_def_id,
upcast_trait_refs
)
};
format!(
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
source_trait_ref, target_trait_def_id, upcast_trait_refs
),
);
*upcast_trait_ref
ty::Binder::dummy(ty::TraitRef::new_from_args(
self.tcx,
target_trait_def_id,
ty::GenericArgs::extend_with_error(self.tcx, target_trait_def_id, &[]),
))
}
}
fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T

View file

@ -7,6 +7,7 @@ edition = "2021"
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_lowering = { path = "../rustc_ast_lowering" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
rustc_data_structures = { path = "../rustc_data_structures" }

View file

@ -1,5 +1,6 @@
//! Checks validity of naked functions.
use rustc_abi::ExternAbi;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
@ -11,7 +12,6 @@ use rustc_middle::span_bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_span::{Span, sym};
use rustc_target::spec::abi::Abi;
use crate::errors::{
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
@ -61,8 +61,8 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
}
/// Checks that function uses non-Rust ABI.
fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: ExternAbi) {
if abi == ExternAbi::Rust {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
tcx.emit_node_span_lint(

View file

@ -4,6 +4,7 @@
use std::mem::replace;
use std::num::NonZero;
use rustc_ast_lowering::stability::extern_abi_stability;
use rustc_attr_parsing::{
self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
UnstableReason, VERSION_PLACEHOLDER,
@ -1027,8 +1028,8 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
if let TyKind::Never = t.kind {
self.fully_stable = false;
}
if let TyKind::BareFn(f) = t.kind {
if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() {
if let TyKind::BareFn(function) = t.kind {
if extern_abi_stability(function.abi).is_err() {
self.fully_stable = false;
}
}

View file

@ -193,6 +193,7 @@ symbols! {
Cleanup,
Clone,
CoercePointee,
CoercePointeeValidated,
CoerceUnsized,
Command,
ConstParamTy,
@ -619,6 +620,7 @@ symbols! {
cmp_partialord_lt,
cmpxchg16b_target_feature,
cmse_nonsecure_entry,
coerce_pointee_validated,
coerce_unsized,
cold,
cold_path,
@ -1024,6 +1026,7 @@ symbols! {
generic_const_exprs,
generic_const_items,
generic_param_attrs,
generic_pattern_types,
get_context,
global_alloc_ty,
global_allocator,

View file

@ -57,13 +57,6 @@ use crate::spec::crt_objects::CrtObjects;
pub mod crt_objects;
pub mod abi {
pub use rustc_abi::{
AbiDisabled, AbiUnsupported, ExternAbi as Abi, all_names, enabled_names, is_enabled,
is_stable, lookup,
};
}
mod base;
mod json;

View file

@ -8,8 +8,9 @@ use rustc_middle::ty::{
self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_span::Span;
use rustc_session::parse::feature_err;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{Span, sym};
use tracing::{debug, instrument, trace};
use crate::infer::InferCtxt;
@ -704,8 +705,47 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
));
}
ty::Pat(subty, _) => {
ty::Pat(subty, pat) => {
self.require_sized(subty, ObligationCauseCode::Misc);
match *pat {
ty::PatternKind::Range { start, end, include_end: _ } => {
let mut check = |c| {
let cause = self.cause(ObligationCauseCode::Misc);
self.out.push(traits::Obligation::with_depth(
tcx,
cause.clone(),
self.recursion_depth,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::ConstArgHasType(c, subty),
)),
));
if !tcx.features().generic_pattern_types() {
if c.has_param() {
if self.span.is_dummy() {
self.tcx().dcx().delayed_bug(
"feature error should be reported elsewhere, too",
);
} else {
feature_err(
&self.tcx().sess,
sym::generic_pattern_types,
self.span,
"wraparound pattern type ranges cause monomorphization time errors",
)
.emit();
}
}
}
};
if let Some(start) = start {
check(start)
}
if let Some(end) = end {
check(end)
}
}
}
}
ty::Tuple(tys) => {