Auto merge of #137651 - fmease:rollup-s3s7m6f, r=fmease

Rollup of 14 pull requests

Successful merges:

 - #136576 (pass optimization level to llvm-bitcode-linker)
 - #137154 (Add UTF-8 validation fast paths in `Wtf8Buf`)
 - #137311 (Enable `f16` for MIPS)
 - #137320 (fix(rustdoc): Fixed stability version in rustdoc)
 - #137529 (remove few unused args)
 - #137544 (tests: Add regression test for derive token invalidation (#81099))
 - #137559 (run some tests on emscripten again)
 - #137601 (ssa/mono: deduplicate `type_has_metadata`)
 - #137603 (codegen_llvm: avoid `Deref` impls w/ extern type)
 - #137604 (trait_sel: resolve vars in host effects)
 - #137609 (Complete the list of resources used in rustdoc output)
 - #137613 (hir_analysis: skip self type of host effect preds in variances_of)
 - #137614 (fix doc in library/core/src/pin.rs)
 - #137622 (fix attribute-related ICE when parsing macro on the rhs of a name-value attribute)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-02-26 06:21:59 +00:00
commit 2b3cef882a
48 changed files with 487 additions and 119 deletions

View File

@ -333,7 +333,10 @@ impl<'sess> AttributeParser<'sess> {
{
lit
} else {
let guar = self.dcx().has_errors().unwrap();
let guar = self.dcx().span_delayed_bug(
args.span().unwrap_or(DUMMY_SP),
"expr in place where literal is expected (builtin attr parsing)",
);
ast::MetaItemLit {
symbol: kw::Empty,
suffix: None,

View File

@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust;
use rustc_errors::DiagCtxtHandle;
use rustc_hir::{self as hir, AttrPath};
use rustc_span::symbol::{Ident, kw};
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
pub struct SegmentIterator<'a> {
offset: usize,
@ -127,7 +127,7 @@ impl<'a> ArgParser<'a> {
}
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
eq_span: *eq_span,
value: expr_to_lit(dcx, &expr),
value: expr_to_lit(dcx, &expr, *eq_span),
value_span: expr.span,
}),
}
@ -348,7 +348,7 @@ impl NameValueParser {
}
}
fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr) -> MetaItemLit {
fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit {
// In valid code the value always ends up as a single literal. Otherwise, a dummy
// literal suffices because the error is handled elsewhere.
if let ExprKind::Lit(token_lit) = expr.kind
@ -356,8 +356,11 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr) -> MetaItemLit {
{
lit
} else {
let guar = dcx.has_errors().unwrap();
MetaItemLit { symbol: kw::Empty, suffix: None, kind: LitKind::Err(guar), span: DUMMY_SP }
let guar = dcx.span_delayed_bug(
span,
"expr in place where literal is expected (builtin attr parsing)",
);
MetaItemLit { symbol: kw::Empty, suffix: None, kind: LitKind::Err(guar), span }
}
}

View File

@ -648,7 +648,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
| StatementKind::StorageLive(..) => {}
// This does not affect borrowck
StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
self.check_backward_incompatible_drop(location, (**place, span), state);
self.check_backward_incompatible_drop(location, **place, state);
}
StatementKind::StorageDead(local) => {
self.access_place(
@ -1174,7 +1174,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
fn check_backward_incompatible_drop(
&mut self,
location: Location,
(place, place_span): (Place<'tcx>, Span),
place: Place<'tcx>,
state: &BorrowckDomain,
) {
let tcx = self.infcx.tcx;

View File

@ -793,7 +793,9 @@ pub(crate) unsafe fn optimize_thin_module(
{
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) };
unsafe {
llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target.raw())
};
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
}
@ -823,7 +825,7 @@ pub(crate) unsafe fn optimize_thin_module(
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
if unsafe {
!llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target)
!llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target.raw())
} {
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
}

View File

@ -1,6 +1,5 @@
use std::ffi::{CStr, c_char};
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
use rustc_data_structures::small_c_str::SmallCStr;
@ -80,12 +79,12 @@ impl OwnedTargetMachine {
.map(|tm_unique| Self { tm_unique, phantom: PhantomData })
.ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
}
}
impl Deref for OwnedTargetMachine {
type Target = llvm::TargetMachine;
fn deref(&self) -> &Self::Target {
/// Returns inner `llvm::TargetMachine` type.
///
/// This could be a `Deref` implementation, but `llvm::TargetMachine` is an extern type and
/// `Deref::Target: ?Sized`.
pub fn raw(&self) -> &llvm::TargetMachine {
// SAFETY: constructing ensures we have a valid pointer created by
// llvm::LLVMRustCreateTargetMachine.
unsafe { self.tm_unique.as_ref() }

View File

@ -637,7 +637,7 @@ pub(crate) unsafe fn llvm_optimize(
let result = unsafe {
llvm::LLVMRustOptimize(
module.module_llvm.llmod(),
&*module.module_llvm.tm,
&*module.module_llvm.tm.raw(),
to_pass_builder_opt_level(opt_level),
opt_stage,
cgcx.opts.cg.linker_plugin_lto.enabled(),
@ -875,7 +875,7 @@ pub(crate) unsafe fn codegen(
};
write_output_file(
dcx,
tm,
tm.raw(),
config.no_builtins,
llmod,
&path,
@ -909,7 +909,7 @@ pub(crate) unsafe fn codegen(
write_output_file(
dcx,
tm,
tm.raw(),
config.no_builtins,
llmod,
&obj_out,

View File

@ -405,7 +405,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) {
bundles.push(kcfi_bundle);
}
@ -1433,7 +1433,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) {
bundles.push(kcfi_bundle);
}
@ -1782,7 +1782,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) {
bundles.push(kcfi_bundle);
}

View File

@ -77,7 +77,7 @@ impl<'ll> Funclet<'ll> {
}
pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> {
&self.operand
self.operand.raw()
}
}

View File

@ -205,7 +205,7 @@ pub(crate) unsafe fn create_module<'ll>(
{
let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm.raw());
}
let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) };

View File

@ -1,7 +1,6 @@
#![allow(non_snake_case)]
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::ptr;
use std::str::FromStr;
use std::string::FromUtf8Error;
@ -355,6 +354,16 @@ impl<'a> OperandBundleOwned<'a> {
};
OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() }
}
/// Returns inner `OperandBundle` type.
///
/// This could be a `Deref` implementation, but `OperandBundle` contains an extern type and
/// `Deref::Target: ?Sized`.
pub(crate) fn raw(&self) -> &OperandBundle<'a> {
// SAFETY: The returned reference is opaque and can only used for FFI.
// It is valid for as long as `&self` is.
unsafe { self.raw.as_ref() }
}
}
impl Drop for OperandBundleOwned<'_> {
@ -365,16 +374,6 @@ impl Drop for OperandBundleOwned<'_> {
}
}
impl<'a> Deref for OperandBundleOwned<'a> {
type Target = OperandBundle<'a>;
fn deref(&self) -> &Self::Target {
// SAFETY: The returned reference is opaque and can only used for FFI.
// It is valid for as long as `&self` is.
unsafe { self.raw.as_ref() }
}
}
pub(crate) fn add_module_flag_u32(
module: &Module,
merge_behavior: ModuleFlagMergeBehavior,

View File

@ -331,7 +331,8 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<S
if let Some(feat) = to_llvm_features(sess, feature) {
for llvm_feature in feat {
let cstr = SmallCStr::new(llvm_feature);
if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) }
{
return false;
}
}
@ -453,8 +454,8 @@ pub(crate) fn print(req: &PrintRequest, out: &mut String, sess: &Session) {
require_inited();
let tm = create_informational_target_machine(sess, false);
match req.kind {
PrintKind::TargetCPUs => print_target_cpus(sess, &tm, out),
PrintKind::TargetFeatures => print_target_features(sess, &tm, out),
PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out),
PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out),
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
}
}

View File

@ -1939,14 +1939,14 @@ impl<'a> Linker for LlbcLinker<'a> {
}
fn optimize(&mut self) {
match self.sess.opts.optimize {
self.link_arg(match self.sess.opts.optimize {
OptLevel::No => "-O0",
OptLevel::Less => "-O1",
OptLevel::More => "-O2",
OptLevel::Aggressive => "-O3",
OptLevel::Size => "-Os",
OptLevel::SizeMin => "-Oz",
};
});
}
fn full_relro(&mut self) {}

View File

@ -2,7 +2,7 @@ use rustc_abi::Primitive::{Int, Pointer};
use rustc_abi::{Align, BackendRepr, FieldsShape, Size, TagEncoding, VariantIdx, Variants};
use rustc_middle::mir::PlaceTy;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_middle::{bug, mir};
use tracing::{debug, instrument};
@ -168,7 +168,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
};
let val = PlaceValue {
llval,
llextra: if bx.cx().type_has_metadata(field.ty) { self.val.llextra } else { None },
llextra: if bx.cx().tcx().type_has_metadata(field.ty, bx.cx().typing_env()) {
self.val.llextra
} else {
None
},
align: effective_field_align,
};
val.with_type(field)

View File

@ -3,7 +3,7 @@ use std::assert_matches::assert_matches;
use arrayvec::ArrayVec;
use rustc_abi::{self as abi, FIRST_VARIANT, FieldIdx};
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, mir, span_bug};
use rustc_session::config::OptLevel;
@ -878,7 +878,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let ty = cg_place.layout.ty;
assert!(
if bx.cx().type_has_metadata(ty) {
if bx.cx().tcx().type_has_metadata(ty, bx.cx().typing_env()) {
matches!(val, OperandValue::Pair(..))
} else {
matches!(val, OperandValue::Immediate(..))

View File

@ -1,7 +1,7 @@
use rustc_abi::{AddressSpace, Float, Integer, Reg};
use rustc_middle::bug;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi};
use super::BackendTypes;
@ -84,19 +84,6 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
ty.is_freeze(self.tcx(), self.typing_env())
}
fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
if ty.is_sized(self.tcx(), self.typing_env()) {
return false;
}
let tail = self.tcx().struct_tail_for_codegen(ty, self.typing_env());
match tail.kind() {
ty::Foreign(..) => false,
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
_ => bug!("unexpected unsized tail: {:?}", tail),
}
}
}
impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where

View File

@ -1074,7 +1074,6 @@ fn lower_variant<'tcx>(
def.ctor().map(|(kind, _, def_id)| (kind, def_id.to_def_id())),
discr,
fields,
adt_kind,
parent_did.to_def_id(),
recovered,
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)

View File

@ -198,6 +198,10 @@ fn variance_of_opaque(
ty::ClauseKind::Trait(ty::TraitPredicate {
trait_ref: ty::TraitRef { def_id: _, args, .. },
polarity: _,
})
| ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
trait_ref: ty::TraitRef { def_id: _, args, .. },
constness: _,
}) => {
for arg in &args[1..] {
arg.visit_with(&mut collector);

View File

@ -1116,7 +1116,6 @@ impl<'a> CrateMetadataRef<'a> {
value: self.get_default_field(did.index),
})
.collect(),
adt_kind,
parent_did,
None,
data.is_non_exhaustive,

View File

@ -1184,23 +1184,17 @@ impl VariantDef {
///
/// If someone speeds up attribute loading to not be a performance concern, they can
/// remove this hack and use the constructor `DefId` everywhere.
#[instrument(level = "debug")]
pub fn new(
name: Symbol,
variant_did: Option<DefId>,
ctor: Option<(CtorKind, DefId)>,
discr: VariantDiscr,
fields: IndexVec<FieldIdx, FieldDef>,
adt_kind: AdtKind,
parent_did: DefId,
recover_tainted: Option<ErrorGuaranteed>,
is_field_list_non_exhaustive: bool,
) -> Self {
debug!(
"VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?},
fields = {:?}, adt_kind = {:?}, parent_did = {:?})",
name, variant_did, ctor, discr, fields, adt_kind, parent_did,
);
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
if is_field_list_non_exhaustive {
flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;

View File

@ -208,6 +208,20 @@ impl<'tcx> TyCtxt<'tcx> {
tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(typing_env, ty), || {})
}
/// Returns true if a type has metadata.
pub fn type_has_metadata(self, ty: Ty<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
if ty.is_sized(self, typing_env) {
return false;
}
let tail = self.struct_tail_for_codegen(ty, typing_env);
match tail.kind() {
ty::Foreign(..) => false,
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
_ => bug!("unexpected unsized tail: {:?}", tail),
}
}
/// Returns the deeply last field of nested structures, or the same type if
/// not a structure at all. Corresponds to the only possible unsized field,
/// and its type can be used to determine unsizing strategy.

View File

@ -751,7 +751,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
/// This does not walk the MIR of the constant as that is not needed for codegen, all we need is
/// to ensure that the constant evaluates successfully and walk the result.
#[instrument(skip(self), level = "debug")]
fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) {
fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, _location: Location) {
// No `super_constant` as we don't care about `visit_ty`/`visit_ty_const`.
let Some(val) = self.eval_constant(constant) else { return };
collect_const_value(self.tcx, val, self.used_items);
@ -1043,18 +1043,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
) -> (Ty<'tcx>, Ty<'tcx>) {
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let typing_env = ty::TypingEnv::fully_monomorphized();
let type_has_metadata = |ty: Ty<'tcx>| -> bool {
if ty.is_sized(tcx.tcx, typing_env) {
return false;
}
let tail = tcx.struct_tail_for_codegen(ty, typing_env);
match tail.kind() {
ty::Foreign(..) => false,
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
_ => bug!("unexpected unsized tail: {:?}", tail),
}
};
if type_has_metadata(inner_source) {
if tcx.type_has_metadata(inner_source, typing_env) {
(inner_source, inner_target)
} else {
tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env)

View File

@ -2252,7 +2252,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
#[instrument(level = "debug", skip(self, parent_scope))]
pub(crate) fn make_path_suggestion(
&mut self,
span: Span,
mut path: Vec<Segment>,
parent_scope: &ParentScope<'ra>,
) -> Option<(Vec<Segment>, Option<String>)> {
@ -2480,7 +2479,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// or `use a::{b, c, d}};`
// ^^^^^^^^^^^
let (has_nested, after_crate_name) =
find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span);
find_span_immediately_after_crate_name(self.tcx.sess, import.use_span);
debug!(has_nested, ?after_crate_name);
let source_map = self.tcx.sess.source_map();
@ -2687,11 +2686,7 @@ fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option
/// // ^^^^^^^^^^^^^^^ -- true
/// ```
#[instrument(level = "debug", skip(sess))]
fn find_span_immediately_after_crate_name(
sess: &Session,
module_name: Symbol,
use_span: Span,
) -> (bool, Span) {
fn find_span_immediately_after_crate_name(sess: &Session, use_span: Span) -> (bool, Span) {
let source_map = sess.source_map();
// Using `use issue_59764::foo::{baz, makro};` as an example throughout..

View File

@ -955,11 +955,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} else {
None
};
let err = match self.make_path_suggestion(
span,
import.module_path.clone(),
&import.parent_scope,
) {
let err = match self
.make_path_suggestion(import.module_path.clone(), &import.parent_scope)
{
Some((suggestion, note)) => UnresolvedImportError {
span,
label: None,

View File

@ -31,6 +31,8 @@ pub fn evaluate_host_effect_obligation<'tcx>(
);
}
let ref obligation = selcx.infcx.resolve_vars_if_possible(obligation.clone());
// Force ambiguity for infer self ty.
if obligation.predicate.self_ty().is_ty_var() {
return Err(EvaluationFailure::Ambiguous);

View File

@ -1240,8 +1240,8 @@ impl<Ptr: Deref> Pin<Ptr> {
/// points to is pinned, that is a violation of the API contract and may lead to undefined
/// behavior in later (even safe) operations.
///
/// By using this method, you are also making a promise about the [`Deref`] and
/// [`DerefMut`] implementations of `Ptr`, if they exist. Most importantly, they
/// By using this method, you are also making a promise about the [`Deref`],
/// [`DerefMut`], and [`Drop`] implementations of `Ptr`, if they exist. Most importantly, they
/// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref`
/// will call `DerefMut::deref_mut` and `Deref::deref` *on the pointer type `Ptr`*
/// and expect these methods to uphold the pinning invariants.

View File

@ -107,7 +107,6 @@ fn main() {
("csky", _) => false,
("hexagon", _) => false,
("loongarch64", _) => false,
("mips" | "mips64" | "mips32r6" | "mips64r6", _) => false,
("powerpc" | "powerpc64", _) => false,
("sparc" | "sparc64", _) => false,
("wasm32" | "wasm64", _) => false,

View File

@ -41,13 +41,13 @@ impl AsInner<Wtf8> for Buf {
impl fmt::Debug for Buf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_slice(), f)
fmt::Debug::fmt(&self.inner, f)
}
}
impl fmt::Display for Buf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_slice(), f)
fmt::Display::fmt(&self.inner, f)
}
}

View File

@ -169,6 +169,18 @@ impl fmt::Debug for Wtf8Buf {
}
}
/// Formats the string with unpaired surrogates substituted with the replacement
/// character, U+FFFD.
impl fmt::Display for Wtf8Buf {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(s) = self.as_known_utf8() {
fmt::Display::fmt(s, formatter)
} else {
fmt::Display::fmt(&**self, formatter)
}
}
}
impl Wtf8Buf {
/// Creates a new, empty WTF-8 string.
#[inline]
@ -262,6 +274,18 @@ impl Wtf8Buf {
unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
}
/// Converts the string to UTF-8 without validation, if it was created from
/// valid UTF-8.
#[inline]
fn as_known_utf8(&self) -> Option<&str> {
if self.is_known_utf8 {
// SAFETY: The buffer is known to be valid UTF-8.
Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) })
} else {
None
}
}
/// Reserves capacity for at least `additional` more bytes to be inserted
/// in the given `Wtf8Buf`.
/// The collection may reserve more space to avoid frequent reallocations.
@ -364,7 +388,7 @@ impl Wtf8Buf {
_ => {
// If we'll be pushing a string containing a surrogate, we may
// no longer have UTF-8.
if other.next_surrogate(0).is_some() {
if self.is_known_utf8 && other.next_surrogate(0).is_some() {
self.is_known_utf8 = false;
}

View File

@ -45,6 +45,27 @@ included, and carry their own copyright notices and license terms:
Licensed under the SIL Open Font License, Version 1.1.
See SourceSerif4-LICENSE.md.
* Nanum Barun Gothic Font (NanumBarunGothic.woff2)
Copyright 2010, NAVER Corporation (http://www.nhncorp.com)
with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
Naver NanumPen, Naver NanumGothicEco, NanumGothicEco,
Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight,
NanumGothicLight, NanumBarunGothic, Naver NanumBarunGothic.
https://hangeul.naver.com/2017/nanum
https://github.com/hiun/NanumBarunGothic
Licensed under the SIL Open Font License, Version 1.1.
See NanumBarunGothic-LICENSE.txt.
* Rust logos (rust-logo.svg, favicon.svg, favicon-32x32.png)
Copyright 2025 Rust Foundation.
Licensed under the Creative Commons Attribution license (CC-BY).
https://rustfoundation.org/policy/rust-trademark-policy/
This copyright file is intended to be distributed with rustdoc output.
# REUSE-IgnoreEnd

View File

@ -39,6 +39,16 @@ impl DocFolder for StabilityPropagator<'_, '_> {
let item_stability = self.cx.tcx.lookup_stability(def_id);
let inline_stability =
item.inline_stmt_id.and_then(|did| self.cx.tcx.lookup_stability(did));
let is_glob_export = item.inline_stmt_id.and_then(|id| {
let hir_id = self.cx.tcx.local_def_id_to_hir_id(id);
Some(matches!(
self.cx.tcx.hir_node(hir_id),
rustc_hir::Node::Item(rustc_hir::Item {
kind: rustc_hir::ItemKind::Use(_, rustc_hir::UseKind::Glob),
..
})
))
});
let own_stability = if let Some(item_stab) = item_stability
&& let StabilityLevel::Stable { since: _, allowed_through_unstable_modules } =
item_stab.level
@ -47,6 +57,8 @@ impl DocFolder for StabilityPropagator<'_, '_> {
since: inline_since,
allowed_through_unstable_modules: _,
} = inline_stab.level
&& let Some(is_global_export) = is_glob_export
&& !is_global_export
{
inline_stab.level = StabilityLevel::Stable {
since: inline_since,

View File

@ -16,3 +16,31 @@ pub mod ffi {
//@ has "foo/struct.CStr.html" "//span[@class='sub-heading']/span[@class='since']" "1.0.0"
//@ !has - "//span[@class='sub-heading']/span[@class='since']" "1.99.0"
pub use ffi::CStr;
// https://github.com/rust-lang/rust/issues/137141
#[stable(feature = "futures_api", since = "1.36.0")]
//@ has "foo/task/index.html" "//span[@class='sub-heading']/span[@class='since']" "1.36.0"
//@ !has - "//span[@class='sub-heading']/span[@class='since']" "1.0.0"
pub mod task {
#[doc(inline)]
#[stable(feature = "futures_api", since = "1.36.0")]
//@ has "foo/task/index.html" "//span[@class='sub-heading']/span[@class='since']" "1.36.0"
//@ has "foo/task/ready/index.html" "//span[@class='sub-heading']/span[@class='since']" "1.64.0"
pub use core::task::*;
}
#[stable(feature = "futures_api", since = "1.36.0")]
//@ has "foo/core/index.html" "//span[@class='sub-heading']/span[@class='since']" "1.36.0"
//@ !has - "//span[@class='sub-heading']/span[@class='since']" "1.0.0"
pub mod core {
#[stable(feature = "futures_api", since = "1.36.0")]
//@ has "foo/core/task/index.html" "//span[@class='sub-heading']/span[@class='since']" "1.36.0"
pub mod task {
#[stable(feature = "ready_macro", since = "1.64.0")]
//@ has "foo/core/task/ready/index.html" "//span[@class='sub-heading']/span[@class='since']" "1.64.0"
pub mod ready {
}
}
}

View File

@ -0,0 +1,7 @@
// Tests for the issue in #137589
#[crate_type = foo!()]
//~^ ERROR cannot find macro `foo` in this scope
macro_rules! foo {} //~ ERROR unexpected end of macro invocation
fn main() {}

View File

@ -0,0 +1,20 @@
error: unexpected end of macro invocation
--> $DIR/crate-type-macro-empty.rs:5:1
|
LL | macro_rules! foo {}
| ^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments
error: cannot find macro `foo` in this scope
--> $DIR/crate-type-macro-empty.rs:2:16
|
LL | #[crate_type = foo!()]
| ^^^ consider moving the definition of `foo` before this call
|
note: a macro with the same name exists, but it appears later
--> $DIR/crate-type-macro-empty.rs:5:14
|
LL | macro_rules! foo {}
| ^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,9 @@
// Tests for the issue in #137589
macro_rules! foo {
($x:expr) => {"rlib"}
}
#[crate_type = foo!()] //~ ERROR unexpected end of macro invocation
fn main() {}

View File

@ -0,0 +1,17 @@
error: unexpected end of macro invocation
--> $DIR/crate-type-macro-not-crate.rs:8:16
|
LL | macro_rules! foo {
| ---------------- when calling this macro
...
LL | #[crate_type = foo!()]
| ^^^^^^ missing tokens in macro arguments
|
note: while trying to match meta-variable `$x:expr`
--> $DIR/crate-type-macro-not-crate.rs:5:6
|
LL | ($x:expr) => {"rlib"}
| ^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,8 @@
// Tests for the issue in #137589
#[crate_type = foo!()] //~ ERROR cannot find macro `foo` in this scope
macro_rules! foo {
($x:expr) => {"rlib"}
}
fn main() {}

View File

@ -0,0 +1,14 @@
error: cannot find macro `foo` in this scope
--> $DIR/crate-type-macro-not-found.rs:2:16
|
LL | #[crate_type = foo!()]
| ^^^ consider moving the definition of `foo` before this call
|
note: a macro with the same name exists, but it appears later
--> $DIR/crate-type-macro-not-found.rs:4:14
|
LL | macro_rules! foo {
| ^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,23 @@
// A regression test for issue #81099.
//@ check-pass
//@ proc-macro:test-macros.rs
#![feature(stmt_expr_attributes)]
#![feature(proc_macro_hygiene)]
#[macro_use]
extern crate test_macros;
#[derive(Clone, Copy)]
struct S {
// `print_args` runs twice
// - on eagerly configured `S` (from `impl Copy`), only 11 should be printed
// - on non-configured `S` (from `struct S`), both 10 and 11 should be printed
field: [u8; #[print_attr] {
#[cfg(FALSE)] { 10 }
#[cfg(not(FALSE))] { 11 }
}],
}
fn main() {}

View File

@ -0,0 +1,149 @@
PRINT-ATTR INPUT (DISPLAY): { #[cfg(not(FALSE))] { 11 } }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Group {
delimiter: Brace,
stream: TokenStream [
Punct {
ch: '#',
spacing: Alone,
span: #0 bytes(491..492),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg",
span: #0 bytes(493..496),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "not",
span: #0 bytes(497..500),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
span: #0 bytes(501..506),
},
],
span: #0 bytes(500..507),
},
],
span: #0 bytes(496..508),
},
],
span: #0 bytes(492..509),
},
Group {
delimiter: Brace,
stream: TokenStream [
Literal {
kind: Integer,
symbol: "11",
suffix: None,
span: #0 bytes(513..515),
},
],
span: #0 bytes(511..517),
},
],
span: #0 bytes(452..523),
},
]
PRINT-ATTR INPUT (DISPLAY): { #[cfg(FALSE)] { 10 } #[cfg(not(FALSE))] { 11 } }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Group {
delimiter: Brace,
stream: TokenStream [
Punct {
ch: '#',
spacing: Alone,
span: #0 bytes(462..463),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg",
span: #0 bytes(464..467),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
span: #0 bytes(468..473),
},
],
span: #0 bytes(467..474),
},
],
span: #0 bytes(463..475),
},
Group {
delimiter: Brace,
stream: TokenStream [
Literal {
kind: Integer,
symbol: "10",
suffix: None,
span: #0 bytes(478..480),
},
],
span: #0 bytes(476..482),
},
Punct {
ch: '#',
spacing: Alone,
span: #0 bytes(491..492),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg",
span: #0 bytes(493..496),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "not",
span: #0 bytes(497..500),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
span: #0 bytes(501..506),
},
],
span: #0 bytes(500..507),
},
],
span: #0 bytes(496..508),
},
],
span: #0 bytes(492..509),
},
Group {
delimiter: Brace,
stream: TokenStream [
Literal {
kind: Integer,
symbol: "11",
suffix: None,
span: #0 bytes(513..515),
},
],
span: #0 bytes(511..517),
},
],
span: #0 bytes(452..523),
},
]

View File

@ -1,6 +1,5 @@
//@ run-pass
#![allow(non_camel_case_types)]
//@ ignore-emscripten FIXME(#45351) hits an LLVM assert
#![feature(repr_simd, intrinsics)]
#[repr(simd)]
@ -53,7 +52,6 @@ unsafe fn simd_or<T>(x: T, y: T) -> T;
#[rustc_intrinsic]
unsafe fn simd_xor<T>(x: T, y: T) -> T;
#[rustc_intrinsic]
unsafe fn simd_neg<T>(x: T) -> T;

View File

@ -1,9 +1,7 @@
//@ run-pass
//@ ignore-emscripten FIXME(#45351) hits an LLVM assert
#![feature(repr_simd, intrinsics)]
#[rustc_intrinsic]
unsafe fn simd_cast<T, U>(x: T) -> U;

View File

@ -1,5 +1,4 @@
//@ run-pass
//@ ignore-emscripten FIXME(#45351) hits an LLVM assert
#![feature(repr_simd, intrinsics, concat_idents)]
#![allow(non_camel_case_types)]
@ -14,7 +13,6 @@ struct u32x4(pub [u32; 4]);
#[derive(Copy, Clone)]
struct f32x4(pub [f32; 4]);
#[rustc_intrinsic]
unsafe fn simd_eq<T, U>(x: T, y: T) -> U;
@ -39,11 +37,11 @@ macro_rules! cmp {
let rhs = $rhs;
let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs);
// assume the scalar version is correct/the behaviour we want.
assert!((e.0[0] != 0) == lhs.0[0] .$method(&rhs.0[0]));
assert!((e.0[1] != 0) == lhs.0[1] .$method(&rhs.0[1]));
assert!((e.0[2] != 0) == lhs.0[2] .$method(&rhs.0[2]));
assert!((e.0[3] != 0) == lhs.0[3] .$method(&rhs.0[3]));
}}
assert!((e.0[0] != 0) == lhs.0[0].$method(&rhs.0[0]));
assert!((e.0[1] != 0) == lhs.0[1].$method(&rhs.0[1]));
assert!((e.0[2] != 0) == lhs.0[2].$method(&rhs.0[2]));
assert!((e.0[3] != 0) == lhs.0[3].$method(&rhs.0[3]));
}};
}
macro_rules! tests {
($($lhs: ident, $rhs: ident;)*) => {{
@ -75,9 +73,9 @@ fn main() {
let i2 = i32x4([5, -5, 20, -100]);
let i3 = i32x4([10, -11, 20, -100]);
let u1 = u32x4([10, !11+1, 12, 13]);
let u2 = u32x4([5, !5+1, 20, !100+1]);
let u3 = u32x4([10, !11+1, 20, !100+1]);
let u1 = u32x4([10, !11 + 1, 12, 13]);
let u2 = u32x4([5, !5 + 1, 20, !100 + 1]);
let u3 = u32x4([10, !11 + 1, 20, !100 + 1]);
let f1 = f32x4([10.0, -11.0, 12.0, 13.0]);
let f2 = f32x4([5.0, -5.0, 20.0, -100.0]);

View File

@ -1,5 +1,4 @@
//@ run-pass
//@ ignore-emscripten FIXME(#45351) hits an LLVM assert
#![feature(repr_simd, intrinsics)]
@ -22,7 +21,6 @@ unsafe fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
#[rustc_intrinsic]
unsafe fn simd_extract<T, E>(x: T, idx: u32) -> E;
#[rustc_intrinsic]
unsafe fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;

View File

@ -1,5 +1,4 @@
//@ run-pass
//@ ignore-emscripten FIXME(#45351)
#![feature(repr_simd, test)]
@ -15,9 +14,7 @@ fn main() {
// non-optimized builds
unsafe {
let memory = &mut [0u64; 8] as *mut _ as *mut u8;
let misaligned_ptr: &mut [u8; 32] = {
std::mem::transmute(memory.offset(1))
};
let misaligned_ptr: &mut [u8; 32] = { std::mem::transmute(memory.offset(1)) };
*misaligned_ptr = std::mem::transmute(Mu64([1, 1, 1, 1]));
test::black_box(memory);
}

View File

@ -1,5 +1,4 @@
//@ run-pass
//@ ignore-emscripten FIXME(#45351)
#![feature(repr_simd, intrinsics)]

View File

@ -0,0 +1,36 @@
//@ check-pass
//@ compile-flags: --crate-type=lib
#![no_std]
#![allow(internal_features)]
#![feature(rustc_attrs, min_specialization, const_trait_impl)]
// In the default impl below, `A` is constrained by the projection predicate, and if the host effect
// predicate for `const Foo` doesn't resolve vars, then specialization will fail.
#[const_trait]
trait Foo {}
pub trait Iterator {
type Item;
}
#[rustc_unsafe_specialization_marker]
pub trait MoreSpecificThanIterator: Iterator {}
pub trait Tr {
fn foo();
}
impl<A: const Foo, Iter> Tr for Iter
where
Iter: Iterator<Item = A>,
{
default fn foo() {}
}
impl<A: const Foo, Iter> Tr for Iter
where
Iter: MoreSpecificThanIterator<Item = A>,
{
fn foo() {}
}

View File

@ -0,0 +1,13 @@
#![feature(rustc_attrs, const_trait_impl)]
#![allow(internal_features)]
#![rustc_variance_of_opaques]
#[const_trait]
trait Foo {}
impl const Foo for () {}
fn foo<'a: 'a>() -> impl const Foo {}
//~^ ERROR ['a: *]
fn main() {}

View File

@ -0,0 +1,8 @@
error: ['a: *]
--> $DIR/variance.rs:10:21
|
LL | fn foo<'a: 'a>() -> impl const Foo {}
| ^^^^^^^^^^^^^^
error: aborting due to 1 previous error