Auto merge of #131237 - GuillaumeGomez:rollup-il2i7z7, r=GuillaumeGomez

Rollup of 4 pull requests

Successful merges:

 - #131034 (Implement RFC3695 Allow boolean literals as cfg predicates)
 - #131202 (Use wide pointers consistenly across the compiler)
 - #131230 (Enable `--no-sandbox` option by default for rustdoc GUI tests)
 - #131232 (Week off of reviews to focus on docs)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-10-04 15:28:24 +00:00
commit c39f318c5e
71 changed files with 407 additions and 211 deletions

View File

@ -527,6 +527,16 @@ impl NestedMetaItem {
}
}
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem` or if it's
/// `NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. })`.
pub fn meta_item_or_bool(&self) -> Option<&NestedMetaItem> {
match self {
NestedMetaItem::MetaItem(_item) => Some(self),
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(_), .. }) => Some(self),
_ => None,
}
}
/// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
pub fn meta_item(&self) -> Option<&MetaItem> {
match self {

View File

@ -107,6 +107,8 @@ attr_unknown_version_literal =
attr_unstable_cfg_target_compact =
compact `cfg(target(..))` is experimental and subject to change
attr_unsupported_literal_cfg_boolean =
literal in `cfg` predicate value must be a boolean
attr_unsupported_literal_cfg_string =
literal in `cfg` predicate value must be a string
attr_unsupported_literal_deprecated_kv_pair =

View File

@ -18,7 +18,7 @@ use rustc_session::parse::feature_err;
use rustc_session::{RustcVersion, Session};
use rustc_span::Span;
use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{Symbol, sym};
use rustc_span::symbol::{Symbol, kw, sym};
use crate::fluent_generated;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@ -36,6 +36,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
pub(crate) enum UnsupportedLiteralReason {
Generic,
CfgString,
CfgBoolean,
DeprecatedString,
DeprecatedKvPair,
}
@ -533,7 +534,7 @@ pub struct Condition {
/// Tests if a cfg-pattern matches the cfg set
pub fn cfg_matches(
cfg: &ast::MetaItem,
cfg: &ast::NestedMetaItem,
sess: &Session,
lint_node_id: NodeId,
features: Option<&Features>,
@ -604,12 +605,43 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
/// evaluate individual items.
pub fn eval_condition(
cfg: &ast::MetaItem,
cfg: &ast::NestedMetaItem,
sess: &Session,
features: Option<&Features>,
eval: &mut impl FnMut(Condition) -> bool,
) -> bool {
let dcx = sess.dcx();
let cfg = match cfg {
ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
ast::NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
if let Some(features) = features {
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
// and `true`, and we want to keep the former working without feature gate
gate_cfg(
&((
if *b { kw::True } else { kw::False },
sym::cfg_boolean_literals,
|features: &Features| features.cfg_boolean_literals,
)),
cfg.span(),
sess,
features,
);
}
return *b;
}
_ => {
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
span: cfg.span(),
reason: UnsupportedLiteralReason::CfgBoolean,
is_bytestr: false,
start_point_span: sess.source_map().start_point(cfg.span()),
});
return false;
}
};
match &cfg.kind {
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
try_gate_cfg(sym::version, cfg.span, sess, features);
@ -645,7 +677,7 @@ pub fn eval_condition(
}
ast::MetaItemKind::List(mis) => {
for mi in mis.iter() {
if !mi.is_meta_item() {
if mi.meta_item_or_bool().is_none() {
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
span: mi.span(),
reason: UnsupportedLiteralReason::Generic,
@ -663,23 +695,19 @@ pub fn eval_condition(
.iter()
// We don't use any() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks
.fold(false, |res, mi| {
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
}),
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
sym::all => mis
.iter()
// We don't use all() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks
.fold(true, |res, mi| {
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
}),
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
sym::not => {
let [mi] = mis.as_slice() else {
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
return false;
};
!eval_condition(mi.meta_item().unwrap(), sess, features, eval)
!eval_condition(mi, sess, features, eval)
}
sym::target => {
if let Some(features) = features
@ -700,7 +728,12 @@ pub fn eval_condition(
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
}
res & eval_condition(&mi, sess, features, eval)
res & eval_condition(
&ast::NestedMetaItem::MetaItem(mi),
sess,
features,
eval,
)
})
}
_ => {

View File

@ -206,6 +206,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
let mut diag = Diag::new(dcx, level, match self.reason {
UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
UnsupportedLiteralReason::CfgBoolean => fluent::attr_unsupported_literal_cfg_boolean,
UnsupportedLiteralReason::DeprecatedString => {
fluent::attr_unsupported_literal_deprecated_string
}

View File

@ -6,7 +6,6 @@ use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::PResult;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_parse::parser::attr::AllowLeadingUnsafe;
use rustc_span::Span;
use {rustc_ast as ast, rustc_attr as attr};
@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
})
}
fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
fn parse_cfg<'a>(
cx: &ExtCtxt<'a>,
span: Span,
tts: TokenStream,
) -> PResult<'a, ast::NestedMetaItem> {
let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof {
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
}
let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?;
let cfg = p.parse_meta_item_inner()?;
let _ = p.eat(&token::Comma);

View File

@ -168,7 +168,7 @@ fn main() {
foo(I64X2([0, 0]));
transmute_fat_pointer();
transmute_wide_pointer();
rust_call_abi();
@ -192,7 +192,7 @@ type TwoPtrs = i64;
#[cfg(target_pointer_width = "64")]
type TwoPtrs = i128;
fn transmute_fat_pointer() -> TwoPtrs {
fn transmute_wide_pointer() -> TwoPtrs {
unsafe { transmute::<_, TwoPtrs>("true !") }
}

View File

@ -713,17 +713,17 @@ fn codegen_stmt<'tcx>(
let from_ty = operand.layout().ty;
let to_ty = fx.monomorphize(to_ty);
fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.builtin_deref(true)
.is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty))
}
if is_fat_ptr(fx, from_ty) {
if is_fat_ptr(fx, to_ty) {
// fat-ptr -> fat-ptr
if is_wide_ptr(fx, from_ty) {
if is_wide_ptr(fx, to_ty) {
// wide-ptr -> wide-ptr
lval.write_cvalue(fx, operand.cast_pointer_to(dest_layout));
} else {
// fat-ptr -> thin-ptr
// wide-ptr -> thin-ptr
let (ptr, _extra) = operand.load_scalar_pair(fx);
lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
}

View File

@ -101,7 +101,7 @@ fn clif_pair_type_from_ty<'tcx>(
})
}
/// Is a pointer to this type a fat ptr?
/// Is a pointer to this type a wide ptr?
pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
if ty.is_sized(tcx, ParamEnv::reveal_all()) {
return false;

View File

@ -139,7 +139,7 @@ impl DebugContext {
pointer_type_id
} else {
// FIXME implement debuginfo for fat pointers
// FIXME implement debuginfo for wide pointers
self.placeholder_for_type(tcx, type_dbg, ptr_type)
}
}

View File

@ -478,7 +478,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
span,
name,
ty: in_elem
@ -493,7 +493,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
span,
name,
ty: out_elem

View File

@ -207,7 +207,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
// layout.
if let Abi::Scalar(ref scalar) = self.abi {
// Use a different cache for scalars because pointers to DSTs
// can be either fat or thin (data pointers of fat pointers).
// can be either wide or thin (data pointers of wide pointers).
if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
return ty;
}

View File

@ -7,7 +7,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
use rustc_codegen_ssa::traits::*;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf;
pub(crate) use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
use rustc_middle::{bug, ty};
use rustc_session::config;
pub(crate) use rustc_target::abi::call::*;

View File

@ -34,7 +34,7 @@ use super::utils::{
};
use crate::common::CodegenCx;
use crate::debuginfo::metadata::type_map::build_type_with_children;
use crate::debuginfo::utils::{FatPtrKind, fat_pointer_kind};
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
use crate::llvm::debuginfo::{
DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
DebugNameTableKind,
@ -161,7 +161,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
unique_type_id: UniqueTypeId<'tcx>,
) -> DINodeCreationResult<'ll> {
// The debuginfo generated by this function is only valid if `ptr_type` is really just
// a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
// a (wide) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
assert_eq!(
cx.size_and_align_of(ptr_type),
cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
@ -174,7 +174,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
let data_layout = &cx.tcx.data_layout;
let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
match fat_pointer_kind(cx, pointee_type) {
match wide_pointer_kind(cx, pointee_type) {
None => {
// This is a thin pointer. Create a regular pointer type and give it the correct name.
assert_eq!(
@ -197,7 +197,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
DINodeCreationResult { di_node, already_stored_in_typemap: false }
}
Some(fat_pointer_kind) => {
Some(wide_pointer_kind) => {
type_map::build_type_with_children(
cx,
type_map::stub(
@ -210,7 +210,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
DIFlags::FlagZero,
),
|cx, owner| {
// FIXME: If this fat pointer is a `Box` then we don't want to use its
// FIXME: If this wide pointer is a `Box` then we don't want to use its
// type layout and instead use the layout of the raw pointer inside
// of it.
// The proper way to handle this is to not treat Box as a pointer
@ -227,16 +227,16 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
};
let layout = cx.layout_of(layout_type);
let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
let addr_field = layout.field(cx, abi::WIDE_PTR_ADDR);
let extra_field = layout.field(cx, abi::WIDE_PTR_EXTRA);
let (addr_field_name, extra_field_name) = match fat_pointer_kind {
FatPtrKind::Dyn => ("pointer", "vtable"),
FatPtrKind::Slice => ("data_ptr", "length"),
let (addr_field_name, extra_field_name) = match wide_pointer_kind {
WidePtrKind::Dyn => ("pointer", "vtable"),
WidePtrKind::Slice => ("data_ptr", "length"),
};
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
assert_eq!(abi::WIDE_PTR_ADDR, 0);
assert_eq!(abi::WIDE_PTR_EXTRA, 1);
// The data pointer type is a regular, thin pointer, regardless of whether this
// is a slice or a trait object.
@ -258,7 +258,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
owner,
addr_field_name,
(addr_field.size, addr_field.align.abi),
layout.fields.offset(abi::FAT_PTR_ADDR),
layout.fields.offset(abi::WIDE_PTR_ADDR),
DIFlags::FlagZero,
data_ptr_type_di_node,
),
@ -267,7 +267,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
owner,
extra_field_name,
(extra_field.size, extra_field.align.abi),
layout.fields.offset(abi::FAT_PTR_EXTRA),
layout.fields.offset(abi::WIDE_PTR_EXTRA),
DIFlags::FlagZero,
type_di_node(cx, extra_field.ty),
),
@ -391,7 +391,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
///
/// NOTE: We currently emit just emit the debuginfo for the element type here
/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
/// `*const T` for the `data_ptr` field of the corresponding fat-pointer
/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
/// debuginfo of `&[T]`.
///
/// It would be preferable and more accurate if we emitted a DIArray of T

View File

@ -49,23 +49,23 @@ pub(crate) fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum FatPtrKind {
pub(crate) enum WidePtrKind {
Slice,
Dyn,
}
/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
/// if the second field of the fat pointer is a length or a vtable-pointer.
/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
/// if the second field of the wide pointer is a length or a vtable-pointer.
/// If `pointee_ty` does not require a wide pointer (because it is Sized) then
/// the function returns `None`.
pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
pub(crate) fn wide_pointer_kind<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
pointee_ty: Ty<'tcx>,
) -> Option<FatPtrKind> {
) -> Option<WidePtrKind> {
let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
let layout = cx.layout_of(pointee_tail_ty);
trace!(
"fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
"wide_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
pointee_tail_ty,
layout,
layout.is_unsized()
@ -76,8 +76,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
}
match *pointee_tail_ty.kind() {
ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
ty::Dynamic(..) => Some(FatPtrKind::Dyn),
ty::Str | ty::Slice(_) => Some(WidePtrKind::Slice),
ty::Dynamic(..) => Some(WidePtrKind::Dyn),
ty::Foreign(_) => {
// Assert that pointers to foreign types really are thin:
assert_eq!(
@ -90,7 +90,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
// For all other pointee types we should already have returned None
// at the beginning of the function.
panic!(
"fat_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
"wide_pointer_kind() - Encountered unexpected `pointee_tail_ty`: {pointee_tail_ty:?}"
)
}
}

View File

@ -2185,7 +2185,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
span,
name,
ty: in_elem
@ -2200,7 +2200,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
});
require!(metadata.is_unit(), InvalidMonomorphization::CastFatPointer {
require!(metadata.is_unit(), InvalidMonomorphization::CastWidePointer {
span,
name,
ty: out_elem

View File

@ -199,7 +199,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
// layout.
if let Abi::Scalar(scalar) = self.abi {
// Use a different cache for scalars because pointers to DSTs
// can be either fat or thin (data pointers of fat pointers).
// can be either wide or thin (data pointers of wide pointers).
if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
return llty;
}

View File

@ -82,7 +82,7 @@ codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphizati
codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
codegen_ssa_invalid_monomorphization_cast_wide_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast wide pointer `{$ty}`
codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`

View File

@ -916,8 +916,8 @@ pub enum InvalidMonomorphization<'tcx> {
ret_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = E0511)]
CastFatPointer {
#[diag(codegen_ssa_invalid_monomorphization_cast_wide_pointer, code = E0511)]
CastWidePointer {
#[primary_span]
span: Span,
name: Symbol,

View File

@ -156,7 +156,7 @@ pub struct NativeLib {
pub kind: NativeLibKind,
pub name: Symbol,
pub filename: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub cfg: Option<ast::NestedMetaItem>,
pub verbatim: bool,
pub dll_imports: Vec<cstore::DllImport>,
}

View File

@ -133,9 +133,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
enum LocalRef<'tcx, V> {
Place(PlaceRef<'tcx, V>),
/// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
/// `*p` is the fat pointer that references the actual unsized place.
/// `*p` is the wide pointer that references the actual unsized place.
/// Every time it is initialized, we have to reallocate the place
/// and update the fat pointer. That's the reason why it is indirect.
/// and update the wide pointer. That's the reason why it is indirect.
UnsizedPlace(PlaceRef<'tcx, V>),
/// The backend [`OperandValue`] has already been generated.
Operand(OperandRef<'tcx, V>),
@ -429,7 +429,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Unsized indirect qrguments
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
// As the storage for the indirect argument lives during
// the whole function call, we just copy the fat pointer.
// the whole function call, we just copy the wide pointer.
let llarg = bx.get_param(llarg_idx);
llarg_idx += 1;
let llextra = bx.get_param(llarg_idx);

View File

@ -41,7 +41,7 @@ pub enum OperandValue<V> {
/// The backend value in this variant must be the *immediate* backend type,
/// as returned by [`LayoutTypeCodegenMethods::immediate_backend_type`].
Immediate(V),
/// A pair of immediate LLVM values. Used by fat pointers too.
/// A pair of immediate LLVM values. Used by wide pointers too.
///
/// An `OperandValue` *must* be this variant for any type for which
/// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`.

View File

@ -38,10 +38,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
ref source,
_,
) => {
// The destination necessarily contains a fat pointer, so if
// it's a scalar pair, it's a fat pointer or newtype thereof.
// The destination necessarily contains a wide pointer, so if
// it's a scalar pair, it's a wide pointer or newtype thereof.
if bx.cx().is_backend_scalar_pair(dest.layout) {
// Into-coerce of a thin pointer to a fat pointer -- just
// Into-coerce of a thin pointer to a wide pointer -- just
// use the operand path.
let temp = self.codegen_rvalue_operand(bx, rvalue);
temp.val.store(bx, dest);
@ -519,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if bx.cx().is_backend_scalar_pair(cast) {
OperandValue::Pair(data_ptr, meta)
} else {
// Cast of fat-ptr to thin-ptr is an extraction of data-ptr.
// Cast of wide-ptr to thin-ptr is an extraction of data-ptr.
OperandValue::Immediate(data_ptr)
}
} else {
@ -622,7 +622,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(
OperandValue::Pair(lhs_addr, lhs_extra),
OperandValue::Pair(rhs_addr, rhs_extra),
) => self.codegen_fat_ptr_binop(
) => self.codegen_wide_ptr_binop(
bx,
op,
lhs_addr,
@ -984,7 +984,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
fn codegen_fat_ptr_binop(
fn codegen_wide_ptr_binop(
&mut self,
bx: &mut Bx,
op: mir::BinOp,
@ -1021,7 +1021,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.or(lhs, rhs)
}
_ => {
bug!("unexpected fat ptr binop");
bug!("unexpected wide ptr binop");
}
}
}

View File

@ -204,12 +204,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
assert!(src.layout.ty.is_any_ptr());
assert!(cast_to.ty.is_unsafe_ptr());
// Handle casting any ptr to raw ptr (might be a fat ptr).
// Handle casting any ptr to raw ptr (might be a wide ptr).
if cast_to.size == src.layout.size {
// Thin or fat pointer that just has the ptr kind of target type changed.
// Thin or wide pointer that just has the ptr kind of target type changed.
return interp_ok(ImmTy::from_immediate(**src, cast_to));
} else {
// Casting the metadata away from a fat ptr.
// Casting the metadata away from a wide ptr.
assert_eq!(src.layout.size, 2 * self.pointer_size());
assert_eq!(cast_to.size, self.pointer_size());
assert!(src.layout.ty.is_unsafe_ptr());

View File

@ -1,4 +1,4 @@
A cast between a thin and a fat pointer was attempted.
A cast between a thin and a wide pointer was attempted.
Erroneous code example:
@ -7,18 +7,18 @@ let v = core::ptr::null::<u8>();
v as *const [u8];
```
First: what are thin and fat pointers?
First: what are thin and wide pointers?
Thin pointers are "simple" pointers: they are purely a reference to a memory
address.
Fat pointers are pointers referencing Dynamically Sized Types (also called
Wide pointers are pointers referencing Dynamically Sized Types (also called
DSTs). DSTs don't have a statically known size, therefore they can only exist
behind some kind of pointer that contains additional information. For example,
slices and trait objects are DSTs. In the case of slices, the additional
information the fat pointer holds is their size.
information the wide pointer holds is their size.
To fix this error, don't try to cast directly between thin and fat pointers.
To fix this error, don't try to cast directly between thin and wide pointers.
For more information about type casts, take a look at the section of the
[The Rust Reference][1] on type cast expressions.

View File

@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::{
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
};
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId};
use rustc_ast::{
self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
};
use rustc_attr as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_feature::{
@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> {
}
}
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
let span = meta_item.span;
match meta_item.meta_item_list() {
None => {
@ -464,7 +466,7 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
None
}
Some([single]) => match single.meta_item() {
Some([single]) => match single.meta_item_or_bool() {
Some(meta_item) => Some(meta_item),
None => {
sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });

View File

@ -371,6 +371,8 @@ declare_features! (
(unstable, async_for_loop, "1.77.0", Some(118898)),
/// Allows using C-variadics.
(unstable, c_variadic, "1.34.0", Some(44930)),
/// Allows the use of `#[cfg(<true/false>)]`.
(unstable, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
/// Provides the relocation model information as cfg entry

View File

@ -1105,7 +1105,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
// 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
// No: char, "wide" pointers, compound types
match element_ty.kind() {
ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok

View File

@ -424,7 +424,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
// Here `U = [i32; 3]` and `V = [i32]`. At runtime,
// when this coercion occurs, we would be changing the
// field `ptr` from a thin pointer of type `*mut [i32;
// 3]` to a fat pointer of type `*mut [i32]` (with
// 3]` to a wide pointer of type `*mut [i32]` (with
// extra data `3`). **The purpose of this check is to
// make sure that we know how to do this conversion.**
//

View File

@ -23,17 +23,17 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
hir_typeck_cast_thin_pointer_to_wide_pointer = cannot cast thin pointer `{$expr_ty}` to wide pointer `{$cast_ty}`
.teach_help = Thin pointers are "simple" pointers: they are purely a reference to a
memory address.
Fat pointers are pointers referencing "Dynamically Sized Types" (also
Wide pointers are pointers referencing "Dynamically Sized Types" (also
called DST). DST don't have a statically known size, therefore they can
only exist behind some kind of pointers that contain additional
information. Slices and trait objects are DSTs. In the case of slices,
the additional information the fat pointer holds is their size.
the additional information the wide pointer holds is their size.
To fix this error, don't try to cast directly between thin and fat
To fix this error, don't try to cast directly between thin and wide
pointers.
For more information about casts, take a look at The Book:

View File

@ -66,7 +66,7 @@ pub(crate) struct CastCheck<'tcx> {
}
/// The kind of pointer and associated metadata (thin, length or vtable) - we
/// only allow casts between fat pointers if their metadata have the same
/// only allow casts between wide pointers if their metadata have the same
/// kind.
#[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
enum PointerKind<'tcx> {
@ -162,7 +162,7 @@ enum CastError<'tcx> {
src_kind: PointerKind<'tcx>,
dst_kind: PointerKind<'tcx>,
},
/// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
/// Cast of thin to wide raw ptr (e.g., `*const () as *const [u8]`).
SizedUnsizedCast,
IllegalCast,
NeedDeref,
@ -172,12 +172,12 @@ enum CastError<'tcx> {
NonScalar,
UnknownExprPtrKind,
UnknownCastPtrKind,
/// Cast of int to (possibly) fat raw pointer.
/// Cast of int to (possibly) wide raw pointer.
///
/// Argument is the specific name of the metadata in plain words, such as "a vtable"
/// or "a length". If this argument is None, then the metadata is unknown, for example,
/// when we're typechecking a type parameter with a ?Sized bound.
IntToFatCast(Option<&'static str>),
IntToWideCast(Option<&'static str>),
ForeignNonExhaustiveAdt,
}
@ -545,14 +545,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
err.emit();
}
CastError::SizedUnsizedCast => {
fcx.dcx().emit_err(errors::CastThinPointerToFatPointer {
fcx.dcx().emit_err(errors::CastThinPointerToWidePointer {
span: self.span,
expr_ty: self.expr_ty,
cast_ty: fcx.ty_to_string(self.cast_ty),
teach: fcx.tcx.sess.teach(E0607),
});
}
CastError::IntToFatCast(known_metadata) => {
CastError::IntToWideCast(known_metadata) => {
let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
let expr_ty = fcx.ty_to_string(self.expr_ty);
@ -861,7 +861,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
return Ok(CastKind::PtrPtrCast);
}
// We can't cast to fat pointer if source pointer kind is unknown
// We can't cast to wide pointer if source pointer kind is unknown
let Some(src_kind) = src_kind else {
return Err(CastError::UnknownCastPtrKind);
};
@ -1054,10 +1054,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
match fcx.pointer_kind(m_cast.ty, self.span)? {
None => Err(CastError::UnknownCastPtrKind),
Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
Some(PointerKind::VTable(_)) => Err(CastError::IntToWideCast(Some("a vtable"))),
Some(PointerKind::Length) => Err(CastError::IntToWideCast(Some("a length"))),
Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => {
Err(CastError::IntToFatCast(None))
Err(CastError::IntToWideCast(None))
}
}
}

View File

@ -699,8 +699,8 @@ pub(crate) struct ReplaceWithName {
}
#[derive(Diagnostic)]
#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)]
pub(crate) struct CastThinPointerToFatPointer<'tcx> {
#[diag(hir_typeck_cast_thin_pointer_to_wide_pointer, code = E0607)]
pub(crate) struct CastThinPointerToWidePointer<'tcx> {
#[primary_span]
pub span: Span,
pub expr_ty: Ty<'tcx>,

View File

@ -55,7 +55,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
/// be checked higher up, as is the case with `&expr` and `box expr`), but
/// is useful in determining the concrete type.
///
/// The primary use case is where the expected type is a fat pointer,
/// The primary use case is where the expected type is a wide pointer,
/// like `&[isize]`. For example, consider the following statement:
///
/// let x: &[isize] = &[1, 2, 3];

View File

@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
if oprnd.is_syntactic_place_expr() {
// Places may legitimately have unsized types.
// For example, dereferences of a fat pointer and
// For example, dereferences of a wide pointer and
// the last field of a struct can be unsized.
ExpectHasType(*ty)
} else {

View File

@ -1,7 +1,7 @@
use std::ops::ControlFlow;
use std::path::{Path, PathBuf};
use rustc_ast::{CRATE_NODE_ID, NestedMetaItem};
use rustc_ast::CRATE_NODE_ID;
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::query::LocalCrate;
@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
continue;
};
let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
let [link_cfg] = link_cfg else {
sess.dcx()
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue;
};
let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
sess.dcx()
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue;

View File

@ -25,10 +25,10 @@ pub enum PointerCoercion {
ArrayToPointer,
/// Unsize a pointer/reference value, e.g., `&[T; n]` to
/// `&[T]`. Note that the source could be a thin or fat pointer.
/// This will do things like convert thin pointers to fat
/// `&[T]`. Note that the source could be a thin or wide pointer.
/// This will do things like convert thin pointers to wide
/// pointers, or convert structs containing thin pointers to
/// structs containing fat pointers, or convert between fat
/// structs containing wide pointers, or convert between wide
/// pointers. We don't store the details of how the transform is
/// done (in fact, we don't know that, because it might depend on
/// the precise type parameters). We just store the target

View File

@ -164,17 +164,17 @@ impl Primitive {
}
}
/// The first half of a fat pointer.
/// The first half of a wide pointer.
///
/// - For a trait object, this is the address of the box.
/// - For a slice, this is the base address.
pub const FAT_PTR_ADDR: usize = 0;
pub const WIDE_PTR_ADDR: usize = 0;
/// The second half of a fat pointer.
/// The second half of a wide pointer.
///
/// - For a trait object, this is the address of the vtable.
/// - For a slice, this is the length.
pub const FAT_PTR_EXTRA: usize = 1;
pub const WIDE_PTR_EXTRA: usize = 1;
/// The maximum supported number of lanes in a SIMD vector.
///
@ -312,7 +312,7 @@ pub enum SizeSkeleton<'tcx> {
/// that another SizeSkeleton is of equal size.
Generic(ty::Const<'tcx>),
/// A potentially-fat pointer.
/// A potentially-wide pointer.
Pointer {
/// If true, this pointer is never null.
non_zero: bool,
@ -785,11 +785,11 @@ where
bug!("TyAndLayout::field({:?}): not applicable", this)
}
// Potentially-fat pointers.
// Potentially-wide pointers.
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
assert!(i < this.fields.count());
// Reuse the fat `*T` type as its own thin pointer data field.
// Reuse the wide `*T` type as its own thin pointer data field.
// This provides information about, e.g., DST struct pointees
// (which may have no non-DST form), and will work as long
// as the `Abi` or `FieldsShape` is checked by users.

View File

@ -1589,7 +1589,7 @@ impl<'tcx> Ty<'tcx> {
.map_bound(|fn_sig| fn_sig.output().no_bound_vars().unwrap())
}
/// Returns the type of metadata for (potentially fat) pointers to this type,
/// Returns the type of metadata for (potentially wide) pointers to this type,
/// or the struct tail if the metadata type cannot be determined.
pub fn ptr_metadata_ty_or_tail(
self,
@ -1648,7 +1648,7 @@ impl<'tcx> Ty<'tcx> {
}
}
/// Returns the type of metadata for (potentially fat) pointers to this type.
/// Returns the type of metadata for (potentially wide) pointers to this type.
/// Causes an ICE if the metadata type cannot be determined.
pub fn ptr_metadata_ty(
self,

View File

@ -1137,7 +1137,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
(UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
return Some(fields[1]);
}
// We have an unsizing cast, which assigns the length to fat pointer metadata.
// We have an unsizing cast, which assigns the length to wide pointer metadata.
(
UnOp::PtrMetadata,
Value::Cast {
@ -1421,7 +1421,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
let mut inner = self.simplify_place_value(place, location)?;
// The length information is stored in the fat pointer.
// The length information is stored in the wide pointer.
// Reborrowing copies length information from one pointer to the other.
while let Value::Address { place: borrowed, .. } = self.get(inner)
&& let [PlaceElem::Deref] = borrowed.projection[..]
@ -1430,7 +1430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
inner = borrowed;
}
// We have an unsizing cast, which assigns the length to fat pointer metadata.
// We have an unsizing cast, which assigns the length to wide pointer metadata.
if let Value::Cast { kind, from, to, .. } = self.get(inner)
&& let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
&& let Some(from) = from.builtin_deref(true)

View File

@ -119,7 +119,7 @@
//!
//! #### Unsizing Casts
//! A subtle way of introducing use edges is by casting to a trait object.
//! Since the resulting fat-pointer contains a reference to a vtable, we need to
//! Since the resulting wide-pointer contains a reference to a vtable, we need to
//! instantiate all dyn-compatible methods of the trait, as we need to store
//! pointers to these functions even if they never get called anywhere. This can
//! be seen as a special case of taking a function reference.
@ -661,7 +661,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
let span = self.body.source_info(location).span;
match *rvalue {
// When doing an cast from a regular pointer to a fat pointer, we
// When doing an cast from a regular pointer to a wide pointer, we
// have to instantiate all methods of the trait being cast to, so we
// can build the appropriate vtable.
mir::Rvalue::Cast(
@ -985,7 +985,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
/// ```
///
/// Then the output of this function would be (SomeStruct, SomeTrait) since for
/// constructing the `target` fat-pointer we need the vtable for that pair.
/// constructing the `target` wide-pointer we need the vtable for that pair.
///
/// Things can get more complicated though because there's also the case where
/// the unsized type occurs as a field:
@ -999,7 +999,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
/// ```
///
/// In this case, if `T` is sized, `&ComplexStruct<T>` is a thin pointer. If `T`
/// is unsized, `&SomeStruct` is a fat pointer, and the vtable it points to is
/// is unsized, `&SomeStruct` is a wide pointer, and the vtable it points to is
/// for the pair of `T` (which is a trait) and the concrete type that `T` was
/// originally coerced from:
///

View File

@ -18,7 +18,7 @@ use std::path::Path;
use rustc_ast as ast;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrItem, Attribute, MetaItem, token};
use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diag, FatalError, PResult};
@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
pub fn parse_cfg_attr(
cfg_attr: &Attribute,
psess: &ParseSess,
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";

View File

@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
}
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?;
pub fn parse_cfg_attr(
&mut self,
) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
let cfg_predicate = self.parse_meta_item_inner()?;
self.expect(&token::Comma)?;
// Presumably, the majority of the time there will only be one attr.
@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
/// ```ebnf
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
/// ```
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
match self.parse_unsuffixed_meta_item_lit() {
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
Err(err) => err.cancel(), // we provide a better error below

View File

@ -72,7 +72,7 @@ pub struct NativeLib {
pub name: Symbol,
/// If packed_bundled_libs enabled, actual filename of library is stored.
pub filename: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub cfg: Option<ast::NestedMetaItem>,
pub foreign_module: Option<DefId>,
pub verbatim: Option<bool>,
pub dll_imports: Vec<DllImport>,

View File

@ -544,6 +544,7 @@ symbols! {
cfg_accessible,
cfg_attr,
cfg_attr_multi,
cfg_boolean_literals,
cfg_doctest,
cfg_eval,
cfg_fmt_debug,

View File

@ -637,7 +637,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
}
}
/// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead.
/// Pass this argument indirectly, by passing a (thin or wide) pointer to the argument instead.
/// This is valid for both sized and unsized arguments.
pub fn make_indirect(&mut self) {
match self.mode {

View File

@ -135,7 +135,7 @@ impl<'a> Layout<'a> {
/// Note that the layout is NOT guaranteed to always be identical
/// to that obtained from `layout_of(ty)`, as we need to produce
/// layouts for which Rust types do not exist, such as enum variants
/// or synthetic fields of enums (i.e., discriminants) and fat pointers.
/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
pub struct TyAndLayout<'a, Ty> {
pub ty: Ty,

View File

@ -1,7 +1,7 @@
use std::iter;
use std::path::PathBuf;
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem};
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::codes::*;
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
#[derive(Debug)]
pub struct OnUnimplementedDirective {
pub condition: Option<MetaItem>,
pub condition: Option<NestedMetaItem>,
pub subcommands: Vec<OnUnimplementedDirective>,
pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>,
@ -414,7 +414,7 @@ impl<'tcx> OnUnimplementedDirective {
let cond = item_iter
.next()
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
.meta_item()
.meta_item_or_bool()
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
if let Some(value) = cfg.value
@ -558,8 +558,8 @@ impl<'tcx> OnUnimplementedDirective {
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
directive.condition.as_ref().map(|i| i.span),
aggr.condition.as_ref().map(|i| i.span),
directive.condition.as_ref().map(|i| i.span()),
aggr.condition.as_ref().map(|i| i.span()),
"condition",
);
IgnoredDiagnosticOption::maybe_emit_warning(

View File

@ -357,7 +357,7 @@ fn fn_abi_of_instance<'tcx>(
)
}
// Handle safe Rust thin and fat pointers.
// Handle safe Rust thin and wide pointers.
fn adjust_for_rust_scalar<'tcx>(
cx: LayoutCx<'tcx>,
attrs: &mut ArgAttributes,
@ -810,7 +810,7 @@ fn make_thin_self_ptr<'tcx>(
layout: TyAndLayout<'tcx>,
) -> TyAndLayout<'tcx> {
let tcx = cx.tcx();
let fat_pointer_ty = if layout.is_unsized() {
let wide_pointer_ty = if layout.is_unsized() {
// unsized `self` is passed as a pointer to `self`
// FIXME (mikeyhew) change this to use &own if it is ever added to the language
Ty::new_mut_ptr(tcx, layout.ty)
@ -825,15 +825,15 @@ fn make_thin_self_ptr<'tcx>(
// elsewhere in the compiler as a method on a `dyn Trait`.
// To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
// get a built-in pointer type
let mut fat_pointer_layout = layout;
while !fat_pointer_layout.ty.is_unsafe_ptr() && !fat_pointer_layout.ty.is_ref() {
fat_pointer_layout = fat_pointer_layout
let mut wide_pointer_layout = layout;
while !wide_pointer_layout.ty.is_unsafe_ptr() && !wide_pointer_layout.ty.is_ref() {
wide_pointer_layout = wide_pointer_layout
.non_1zst_field(cx)
.expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type")
.1
}
fat_pointer_layout.ty
wide_pointer_layout.ty
};
// we now have a type like `*mut RcBox<dyn Trait>`
@ -842,7 +842,7 @@ fn make_thin_self_ptr<'tcx>(
let unit_ptr_ty = Ty::new_mut_ptr(tcx, tcx.types.unit);
TyAndLayout {
ty: fat_pointer_ty,
ty: wide_pointer_ty,
// NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
// should always work because the type is always `*mut ()`.

View File

@ -946,10 +946,10 @@ pub enum PointerCoercion {
ArrayToPointer,
/// Unsize a pointer/reference value, e.g., `&[T; n]` to
/// `&[T]`. Note that the source could be a thin or fat pointer.
/// This will do things like convert thin pointers to fat
/// `&[T]`. Note that the source could be a thin or wide pointer.
/// This will do things like convert thin pointers to wide
/// pointers, or convert structs containing thin pointers to
/// structs containing fat pointers, or convert between fat
/// structs containing wide pointers, or convert between wide
/// pointers.
Unsize,
}

View File

@ -100,4 +100,4 @@ RUN /scripts/build-gccjit.sh /scripts
# the local version of the package is different than the one used by the CI.
ENV SCRIPT /tmp/checktools.sh ../x.py && \
npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \
python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'"
python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"

View File

@ -0,0 +1,22 @@
# `cfg_boolean_literals`
The tracking issue for this feature is: [#131204]
[#131204]: https://github.com/rust-lang/rust/issues/131204
------------------------
The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
literal as cfg predicate. They always evaluate to true/false respectively.
## Examples
```rust
#![feature(cfg_boolean_literals)]
#[cfg(true)]
const A: i32 = 5;
#[cfg(all(false))]
const A: i32 = 58 * 89;
```

View File

@ -6,7 +6,7 @@
use std::fmt::{self, Write};
use std::{mem, ops};
use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem};
use rustc_ast::{LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem};
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::Features;
use rustc_session::parse::ParseSess;
@ -48,6 +48,10 @@ impl Cfg {
) -> Result<Option<Cfg>, InvalidCfgError> {
match nested_cfg {
NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude),
NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b {
true => Ok(Some(Cfg::True)),
false => Ok(Some(Cfg::False)),
},
NestedMetaItem::Lit(ref lit) => {
Err(InvalidCfgError { msg: "unexpected literal", span: lit.span })
}
@ -120,8 +124,8 @@ impl Cfg {
///
/// If the content is not properly formatted, it will return an error indicating what and where
/// the error is.
pub(crate) fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
pub(crate) fn parse(cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap())
}
/// Checks whether the given configuration can be matched in the current session.

View File

@ -1,4 +1,5 @@
use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
use rustc_ast::ast::LitIntType;
use rustc_ast::{MetaItemLit, NestedMetaItem, Path, Safety, StrStyle};
use rustc_span::symbol::{Ident, kw};
use rustc_span::{DUMMY_SP, create_default_session_globals_then};
use thin_vec::thin_vec;
@ -13,52 +14,52 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg {
Cfg::Cfg(Symbol::intern(name), Some(Symbol::intern(value)))
}
fn dummy_meta_item_word(name: &str) -> MetaItem {
MetaItem {
fn dummy_lit(symbol: Symbol, kind: LitKind) -> NestedMetaItem {
NestedMetaItem::Lit(MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP })
}
fn dummy_meta_item_word(name: &str) -> NestedMetaItem {
NestedMetaItem::MetaItem(MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(name)),
kind: MetaItemKind::Word,
span: DUMMY_SP,
}
})
}
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> NestedMetaItem {
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
MetaItem {
NestedMetaItem::MetaItem(MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(name)),
kind: MetaItemKind::NameValue(lit),
span: DUMMY_SP,
}
})
}
macro_rules! dummy_meta_item_list {
($name:ident, [$($list:ident),* $(,)?]) => {
MetaItem {
NestedMetaItem::MetaItem(MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(stringify!($name))),
kind: MetaItemKind::List(thin_vec![
$(
NestedMetaItem::MetaItem(
dummy_meta_item_word(stringify!($list)),
),
dummy_meta_item_word(stringify!($list)),
)*
]),
span: DUMMY_SP,
}
})
};
($name:ident, [$($list:expr),* $(,)?]) => {
MetaItem {
NestedMetaItem::MetaItem(MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(stringify!($name))),
kind: MetaItemKind::List(thin_vec![
$(
NestedMetaItem::MetaItem($list),
)*
$($list,)*
]),
span: DUMMY_SP,
}
})
};
}
@ -251,6 +252,14 @@ fn test_cfg_or() {
#[test]
fn test_parse_ok() {
create_default_session_globals_then(|| {
let r#true = Symbol::intern("true");
let mi = dummy_lit(r#true, LitKind::Bool(true));
assert_eq!(Cfg::parse(&mi), Ok(Cfg::True));
let r#false = Symbol::intern("false");
let mi = dummy_lit(r#false, LitKind::Bool(false));
assert_eq!(Cfg::parse(&mi), Ok(Cfg::False));
let mi = dummy_meta_item_word("all");
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
@ -309,6 +318,14 @@ fn test_parse_err() {
let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]);
assert!(Cfg::parse(&mi).is_err());
let c = Symbol::intern("e");
let mi = dummy_lit(c, LitKind::Char('e'));
assert!(Cfg::parse(&mi).is_err());
let five = Symbol::intern("5");
let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed));
assert!(Cfg::parse(&mi).is_err());
})
}

View File

@ -5,6 +5,7 @@ use std::sync::{Arc, OnceLock as OnceCell};
use std::{fmt, iter};
use arrayvec::ArrayVec;
use rustc_ast::NestedMetaItem;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
use rustc_const_eval::const_eval::is_unstable_const_fn;
@ -986,7 +987,7 @@ pub(crate) trait AttributesExt {
.peekable();
if doc_cfg.peek().is_some() && doc_cfg_active {
doc_cfg
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
.filter_map(|attr| Cfg::parse(&attr).ok())
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
} else if doc_auto_cfg_active {
// If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
@ -1042,7 +1043,7 @@ pub(crate) trait AttributesExt {
let mut meta = attr.meta_item().unwrap().clone();
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
if let Ok(feat_cfg) = Cfg::parse(&meta) {
if let Ok(feat_cfg) = Cfg::parse(&NestedMetaItem::MetaItem(meta)) {
cfg &= feat_cfg;
}
}

View File

@ -164,7 +164,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
.unwrap_or(&[])
.iter()
.filter_map(|attr| {
Cfg::parse(attr.meta_item()?)
Cfg::parse(attr)
.map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
.ok()
})

View File

@ -19,7 +19,6 @@ function showHelp() {
console.log(" --debug : show extra information about script run");
console.log(" --show-text : render font in pages");
console.log(" --no-headless : disable headless mode");
console.log(" --no-sandbox : disable sandbox mode");
console.log(" --help : show this message then quit");
console.log(" --tests-folder [PATH] : location of the .GOML tests folder");
console.log(" --jobs [NUMBER] : number of threads to run tests on");
@ -40,7 +39,6 @@ function parseOptions(args) {
"no_headless": false,
"jobs": -1,
"executable_path": null,
"no_sandbox": false,
};
const correspondences = {
"--doc-folder": "doc_folder",
@ -49,7 +47,6 @@ function parseOptions(args) {
"--show-text": "show_text",
"--no-headless": "no_headless",
"--executable-path": "executable_path",
"--no-sandbox": "no_sandbox",
};
for (let i = 0; i < args.length; ++i) {
@ -80,9 +77,6 @@ function parseOptions(args) {
} else if (arg === "--help") {
showHelp();
process.exit(0);
} else if (arg === "--no-sandbox") {
console.log("`--no-sandbox` is being used. Be very careful!");
opts[correspondences[arg]] = true;
} else if (correspondences[arg]) {
opts[correspondences[arg]] = true;
} else {
@ -203,6 +197,7 @@ async function main(argv) {
const args = [
"--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
"--enable-fail-on-js-error", "--allow-file-access-from-files",
"--no-sandbox",
];
if (opts["debug"]) {
debug = true;
@ -211,9 +206,6 @@ async function main(argv) {
if (opts["show_text"]) {
args.push("--show-text");
}
if (opts["no_sandbox"]) {
args.push("--no-sandbox");
}
if (opts["no_headless"]) {
args.push("--no-headless");
headless = false;
@ -262,19 +254,6 @@ async function main(argv) {
console.log(`Running ${files.length} rustdoc-gui ...`);
}
// We catch this "event" to display a nicer message in case of unexpected exit (because of a
// missing `--no-sandbox`).
const exitHandling = () => {
if (!opts["no_sandbox"]) {
console.log("");
console.log(
"`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \
--no-sandbox` at the end. For example: `x.py test tests/rustdoc-gui --test-args --no-sandbox`");
console.log("");
}
};
process.on("exit", exitHandling);
const originalFilesLen = files.length;
const results = createEmptyResults();
const status_bar = char_printer(files.length);
@ -299,9 +278,6 @@ async function main(argv) {
Array.prototype.push.apply(results.failed, new_results.failed);
Array.prototype.push.apply(results.errored, new_results.errored);
// We don't need this listener anymore.
process.removeListener("exit", exitHandling);
if (debug) {
results.successful.sort(by_filename);
results.successful.forEach(r => {

View File

@ -23,12 +23,5 @@ $ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-headless
To see the supported options, use `--help`.
Important to be noted: if the chromium instance crashes when you run it, you might need to
use `--no-sandbox` to make it work:
```bash
$ ./x.py test tests/rustdoc-gui --stage 1 --test-args --no-sandbox
```
[browser-ui-test]: https://github.com/GuillaumeGomez/browser-UI-test/
[puppeteer]: https://pptr.dev/

View File

@ -0,0 +1,19 @@
//@ check-pass
#![feature(cfg_boolean_literals)]
#![feature(doc_cfg)]
#[doc(cfg(false))]
pub fn foo() {}
#[doc(cfg(true))]
pub fn bar() {}
#[doc(cfg(any(true)))]
pub fn zoo() {}
#[doc(cfg(all(true)))]
pub fn toy() {}
#[doc(cfg(not(true)))]
pub fn nay() {}

View File

@ -44,7 +44,7 @@ LL | p as usize;
|
= help: cast through a thin pointer first
error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]`
error[E0607]: cannot cast thin pointer `*const i32` to wide pointer `*const [i32]`
--> $DIR/fat-ptr-cast.rs:19:5
|
LL | q as *const [i32];

View File

@ -0,0 +1,19 @@
//@ check-pass
//@ compile-flags: --cfg false --check-cfg=cfg(r#false)
#![deny(warnings)]
#[expect(unexpected_cfgs)]
mod a {
#[cfg(r#true)]
pub fn foo() {}
}
mod b {
#[cfg(r#false)]
pub fn bar() {}
}
fn main() {
b::bar()
}

View File

@ -0,0 +1,30 @@
//@ run-pass
#![feature(link_cfg)]
#![feature(cfg_boolean_literals)]
#[cfg(true)]
fn foo() -> bool {
cfg!(true)
}
#[cfg(false)]
fn foo() -> bool {
cfg!(false)
}
#[cfg_attr(true, cfg(false))]
fn foo() {}
#[link(name = "foo", cfg(false))]
extern "C" {}
fn main() {
assert!(foo());
assert!(cfg!(true));
assert!(!cfg!(false));
assert!(cfg!(not(false)));
assert!(cfg!(all(true)));
assert!(cfg!(any(true)));
assert!(!cfg!(not(true)));
}

View File

@ -1,4 +1,4 @@
error[E0607]: cannot cast thin pointer `*const [i64; 0]` to fat pointer `*const [u8]`
error[E0607]: cannot cast thin pointer `*const [i64; 0]` to wide pointer `*const [u8]`
--> $DIR/slice_elem_ty_mismatch_in_unsizing_cast.rs:1:31
|
LL | const FOO: &str = unsafe { &*(1_usize as *const [i64; 0] as *const [u8] as *const str) };

View File

@ -1,4 +1,4 @@
error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]`
--> $DIR/E0607.rs:3:5
|
LL | v as *const [u8];

View File

@ -81,7 +81,7 @@ help: dereference the expression
LL | let y: u32 = *x as u32;
| +
error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]`
--> $DIR/error-festival.rs:41:5
|
LL | v as *const [u8];

View File

@ -0,0 +1,10 @@
#[cfg(true)] //~ ERROR `cfg(true)` is experimental
fn foo() {}
#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental
//~^ ERROR `cfg(false)` is experimental
fn foo() {}
fn main() {
cfg!(false); //~ ERROR `cfg(false)` is experimental
}

View File

@ -0,0 +1,43 @@
error[E0658]: `cfg(true)` is experimental and subject to change
--> $DIR/feature-gate-cfg-boolean-literals.rs:1:7
|
LL | #[cfg(true)]
| ^^^^
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `cfg(true)` is experimental and subject to change
--> $DIR/feature-gate-cfg-boolean-literals.rs:4:12
|
LL | #[cfg_attr(true, cfg(false))]
| ^^^^
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `cfg(false)` is experimental and subject to change
--> $DIR/feature-gate-cfg-boolean-literals.rs:4:22
|
LL | #[cfg_attr(true, cfg(false))]
| ^^^^^
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `cfg(false)` is experimental and subject to change
--> $DIR/feature-gate-cfg-boolean-literals.rs:9:10
|
LL | cfg!(false);
| ^^^^^
|
= note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
= help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,6 +1,6 @@
fn cast_thin_to_fat(x: *const ()) {
x as *const [u8];
//~^ ERROR: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]`
//~^ ERROR: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]`
}
fn main() {}

View File

@ -1,4 +1,4 @@
error[E0607]: cannot cast thin pointer `*const ()` to fat pointer `*const [u8]`
error[E0607]: cannot cast thin pointer `*const ()` to wide pointer `*const [u8]`
--> $DIR/issue-31511.rs:2:5
|
LL | x as *const [u8];

View File

@ -1,6 +1,6 @@
fn main() {
cfg!(); //~ ERROR macro requires a cfg-pattern
cfg!(123); //~ ERROR expected identifier
cfg!(123); //~ ERROR literal in `cfg` predicate value must be a boolean
cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string
cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
}

View File

@ -6,11 +6,11 @@ LL | cfg!();
|
= note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected identifier, found `123`
error[E0565]: literal in `cfg` predicate value must be a boolean
--> $DIR/cfg.rs:3:10
|
LL | cfg!(123);
| ^^^ expected identifier
| ^^^
error[E0565]: literal in `cfg` predicate value must be a string
--> $DIR/cfg.rs:4:16

View File

@ -158,7 +158,7 @@ LL | let _ = 42usize as *const [u8];
| |
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]`
--> $DIR/cast-rfc0401.rs:52:13
|
LL | let _ = v as *const [u8];

View File

@ -925,6 +925,7 @@ users_on_vacation = [
"jhpratt",
"jyn514",
"oli-obk",
"jieyouxu",
]
[assign.adhoc_groups]