diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index e56ed166592aa..b215f77c39adb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -236,9 +236,11 @@ fn parse_directive_items<'p, S: Stage>( }} macro or_malformed($($code:tt)*) {{ - let Some(ret) = (||{ - Some($($code)*) - })() else { + let Some(ret) = ( + try { + $($code)* + } + ) else { malformed!() }; ret diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cebbabfcbf1be..4aa7ebffbd3cf 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -84,8 +84,7 @@ pub(super) struct GroupTypeInnerAccept { pub(crate) type AcceptFn = Box Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>; -pub(crate) type FinalizeFn = - Box) -> Option>; +pub(crate) type FinalizeFn = fn(&mut FinalizeContext<'_, '_, S>) -> Option; macro_rules! attribute_parsers { ( @@ -131,10 +130,10 @@ macro_rules! attribute_parsers { }), safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY, allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS, - finalizer: Box::new(|cx| { + finalizer: |cx| { let state = STATE_OBJECT.take(); state.finalize(cx) - }) + } }); } Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"), diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 0dfa67951e629..d350bfee7f348 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -297,7 +297,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let mut attr_paths: Vec> = Vec::new(); let mut early_parsed_state = EarlyParsedState::default(); - let mut finalizers: Vec<&FinalizeFn> = Vec::with_capacity(attrs.len()); + let mut finalizers: Vec> = Vec::with_capacity(attrs.len()); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -413,7 +413,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }; (accept.accept_fn)(&mut cx, &args); - finalizers.push(&accept.finalizer); + finalizers.push(accept.finalizer); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { Self::check_target(&accept.allowed_targets, target, &mut cx); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 180559d28d848..32694135705e8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -510,6 +510,9 @@ fn print_target_cpus(sess: &Session, tm: &llvm::TargetMachine, out: &mut String) }; let mut cpus = cpu_names .lines() + .filter(|cpu_name| { + !sess.target.unsupported_cpus.contains(&std::borrow::Cow::Borrowed(*cpu_name)) + }) .map(|cpu_name| Cpu { cpu_name, remark: make_remark(cpu_name) }) .collect::>(); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 5601a950fbdb5..ff91a08de4de6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -153,7 +153,7 @@ impl ModuleConfig { // `#![no_builtins]` is assumed to not participate in LTO and // instead goes on to generate object code. EmitObj::Bitcode - } else if need_bitcode_in_object(tcx) { + } else if need_bitcode_in_object(tcx) || sess.target.requires_lto { EmitObj::ObjectCode(BitcodeSection::Full) } else { EmitObj::ObjectCode(BitcodeSection::None) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 50c439593c306..14f4dca532737 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -696,6 +696,13 @@ pub fn codegen_crate( tcx.dcx().emit_fatal(errors::CpuRequired); } + if let Some(target_cpu) = &tcx.sess.opts.cg.target_cpu + && tcx.sess.target.unsupported_cpus.contains(&target_cpu.into()) + { + // The target cpu is explicitly listed as an unsupported cpu + tcx.dcx().emit_fatal(errors::CpuUnsupported { target_cpu: target_cpu.clone() }); + } + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); // Run the monomorphization collector and partition the collected items into diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f1112510af0f0..006b7f881ce23 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -540,6 +540,12 @@ pub(crate) struct InsufficientVSCodeProduct; #[diag("target requires explicitly specifying a cpu with `-C target-cpu`")] pub(crate) struct CpuRequired; +#[derive(Diagnostic)] +#[diag("target cpu `{$target_cpu}` is known but unsupported")] +pub(crate) struct CpuUnsupported { + pub target_cpu: String, +} + #[derive(Diagnostic)] #[diag("processing debug info with `dsymutil` failed: {$status}")] #[note("{$output}")] diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 24f731c01996d..4b1b0866f2eb9 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -387,8 +387,20 @@ pub fn target_spec_to_backend_features<'a>( sess: &'a Session, mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool), ) { - // Compute implied features let mut rust_features = vec![]; + + // This check handles SM versions that defaults (by LLVM) to unsupported (by Rust) PTX ISA versions. + // sm_70, sm_72 and sm_75 defaults to PTX ISA versions with major version 6, while sm_80 default to 7.0 + if sess.target.arch == Arch::Nvptx64 + && matches!( + sess.opts.cg.target_cpu.as_deref(), + None | Some("sm_70") | Some("sm_72") | Some("sm_75") + ) + { + rust_features.push((true, "ptx70")); + } + + // Compute implied features parse_rust_feature_list( sess, &sess.target.features, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index e34628bad66b4..4dac314b91812 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -2009,6 +2009,9 @@ impl<'tcx> CoerceMany<'tcx> { // note in this case, since it would be incorrect. && let Some(fn_sig) = fcx.body_fn_sig() && fn_sig.output().is_ty_var() + && fcx.ret_coercion.as_ref().is_some_and(|ret_coercion| { + fcx.resolve_vars_if_possible(ret_coercion.borrow().expected_ty()) == expected + }) { err.span_note(sp, format!("return type inferred to be `{expected}` here")); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1f08dff18f3ed..afd5356d5a1e7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -7,6 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::packed::Pu128; use rustc_errors::{Applicability, Diag, MultiSpan, listify, msg}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, @@ -26,13 +27,14 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::{ExpnKind, Ident, MacroKind, Span, Spanned, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::DefIdOrName; +use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use tracing::{debug, instrument}; use super::FnCtxt; -use crate::errors; +use crate::errors::{self, SuggestBoxingForReturnImplTrait}; use crate::fn_ctxt::rustc_span::BytePos; use crate::method::probe; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; @@ -963,6 +965,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + let trait_def_id = trait_ref.trait_ref.path.res.def_id(); + if self.tcx.is_dyn_compatible(trait_def_id) { + err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType { + start_sp: hir_ty.span.with_hi(hir_ty.span.lo() + BytePos(4)), + end_sp: hir_ty.span.shrink_to_hi(), + }); + + let body = self.tcx.hir_body_owned_by(fn_id); + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(&body); + + if !visitor.returns.is_empty() { + let starts: Vec = visitor + .returns + .iter() + .filter(|expr| expr.span.can_be_used_for_suggestions()) + .map(|expr| expr.span.shrink_to_lo()) + .collect(); + let ends: Vec = visitor + .returns + .iter() + .filter(|expr| expr.span.can_be_used_for_suggestions()) + .map(|expr| expr.span.shrink_to_hi()) + .collect(); + + if !starts.is_empty() { + err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr { + starts, + ends, + }); + } + } + } + self.try_suggest_return_impl_trait(err, expected, found, fn_id); self.try_note_caller_chooses_ty_for_ty_param(err, expected, found); return true; diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 90af4d785945b..29ec97a6ca592 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -143,7 +143,7 @@ pub(crate) struct Reentrant; #[note( "an ideal reproduction consists of the code before and some patch that then triggers the bug when applied and compiled again" )] -#[note("as a workaround, you can run {$run_cmd} to allow your project to compile")] +#[note("as a workaround, you can {$run_cmd} to allow your project to compile")] pub(crate) struct IncrementCompilation { pub run_cmd: String, pub dep_node: String, diff --git a/compiler/rustc_middle/src/verify_ich.rs b/compiler/rustc_middle/src/verify_ich.rs index a1ab4d8cc4d00..5aa7a1d91f800 100644 --- a/compiler/rustc_middle/src/verify_ich.rs +++ b/compiler/rustc_middle/src/verify_ich.rs @@ -1,6 +1,8 @@ use std::cell::Cell; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_session::utils::was_invoked_from_cargo; use tracing::instrument; use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex}; @@ -66,10 +68,10 @@ fn incremental_verify_ich_failed<'tcx>( if old_in_panic { tcx.dcx().emit_err(crate::error::Reentrant); } else { - let run_cmd = if let Some(crate_name) = &tcx.sess.opts.crate_name { - format!("`cargo clean -p {crate_name}` or `cargo clean`") + let run_cmd = if was_invoked_from_cargo() { + format!("run `cargo clean -p {}` or `cargo clean`", tcx.crate_name(LOCAL_CRATE)) } else { - "`cargo clean`".to_string() + "clean your build cache".to_owned() }; let dep_node = tcx.dep_graph.data().unwrap().prev_node_of(prev_index); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d84bfeb8fff86..cd9d573957f45 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1205,6 +1205,7 @@ impl OutputFilenames { } pub fn interface_path(&self) -> PathBuf { + debug!("using crate_name={} for interface_path", self.crate_stem); self.out_directory.join(format!("lib{}.rs", self.crate_stem)) } @@ -1214,6 +1215,7 @@ impl OutputFilenames { let extension = flavor.extension(); match flavor { OutputType::Metadata => { + debug!("using crate_name={} for {extension}", self.crate_stem); self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension)) } _ => self.with_directory_and_extension(&self.out_directory, extension), @@ -1288,6 +1290,7 @@ impl OutputFilenames { } pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf { + debug!("using filestem={} for {extension}", self.filestem); let mut path = directory.join(&self.filestem); path.set_extension(extension); path diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 5507af0866758..8448c2ab51b3d 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -116,6 +116,7 @@ impl Target { forward!(asm_args); forward!(cpu); forward!(need_explicit_cpu); + forward!(unsupported_cpus); forward!(features); forward!(dynamic_linking); forward_opt!(direct_access_external_data); @@ -320,6 +321,7 @@ impl ToJson for Target { target_option_val!(asm_args); target_option_val!(cpu); target_option_val!(need_explicit_cpu); + target_option_val!(unsupported_cpus); target_option_val!(features); target_option_val!(dynamic_linking); target_option_val!(direct_access_external_data); @@ -543,6 +545,7 @@ struct TargetSpecJson { asm_args: Option]>>, cpu: Option>, need_explicit_cpu: Option, + unsupported_cpus: Option]>>, features: Option>, dynamic_linking: Option, direct_access_external_data: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 768e43146a0c1..74cf01e77754e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2361,6 +2361,10 @@ pub struct TargetOptions { /// Whether a cpu needs to be explicitly set. /// Set to true if there is no default cpu. Defaults to false. pub need_explicit_cpu: bool, + /// A list of CPUs that are provided by LLVM but are considered unsupported by Rust. + /// These CPUs are omitted from `--print target-cpus` output and will cause an error + /// if used with `-Ctarget-cpu`. + pub unsupported_cpus: StaticCow<[StaticCow]>, /// Default (Rust) target features to enable for this target. These features /// overwrite `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`. /// Corresponds to `llc -mattr=$llvm_features` where `$llvm_features` is the @@ -2818,6 +2822,7 @@ impl Default for TargetOptions { asm_args: cvs![], cpu: "generic".into(), need_explicit_cpu: false, + unsupported_cpus: cvs![], features: "".into(), direct_access_external_data: None, dynamic_linking: false, diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index 87c2693e9877f..d8a0bd50ee204 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -1,6 +1,6 @@ use crate::spec::{ Arch, LinkSelfContainedDefault, LinkerFlavor, MergeFunctions, Os, PanicStrategy, Target, - TargetMetadata, TargetOptions, + TargetMetadata, TargetOptions, cvs, }; pub(crate) fn target() -> Target { @@ -22,7 +22,13 @@ pub(crate) fn target() -> Target { linker_flavor: LinkerFlavor::Llbc, // With `ptx-linker` approach, it can be later overridden via link flags. - cpu: "sm_30".into(), + cpu: "sm_70".into(), + + // No longer supported architectures + unsupported_cpus: cvs!( + "sm_20", "sm_21", "sm_30", "sm_32", "sm_35", "sm_37", "sm_50", "sm_52", "sm_53", + "sm_60", "sm_61", "sm_62" + ), // FIXME: create tests for the atomics. max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 9040c4eb1e399..498806f8c1c51 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -536,19 +536,7 @@ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("sm_20", Unstable(sym::nvptx_target_feature), &[]), - ("sm_21", Unstable(sym::nvptx_target_feature), &["sm_20"]), - ("sm_30", Unstable(sym::nvptx_target_feature), &["sm_21"]), - ("sm_32", Unstable(sym::nvptx_target_feature), &["sm_30"]), - ("sm_35", Unstable(sym::nvptx_target_feature), &["sm_32"]), - ("sm_37", Unstable(sym::nvptx_target_feature), &["sm_35"]), - ("sm_50", Unstable(sym::nvptx_target_feature), &["sm_37"]), - ("sm_52", Unstable(sym::nvptx_target_feature), &["sm_50"]), - ("sm_53", Unstable(sym::nvptx_target_feature), &["sm_52"]), - ("sm_60", Unstable(sym::nvptx_target_feature), &["sm_53"]), - ("sm_61", Unstable(sym::nvptx_target_feature), &["sm_60"]), - ("sm_62", Unstable(sym::nvptx_target_feature), &["sm_61"]), - ("sm_70", Unstable(sym::nvptx_target_feature), &["sm_62"]), + ("sm_70", Unstable(sym::nvptx_target_feature), &[]), ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]), ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]), ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]), @@ -567,19 +555,7 @@ const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]), // tidy-alphabetical-end // tidy-alphabetical-start - ("ptx32", Unstable(sym::nvptx_target_feature), &[]), - ("ptx40", Unstable(sym::nvptx_target_feature), &["ptx32"]), - ("ptx41", Unstable(sym::nvptx_target_feature), &["ptx40"]), - ("ptx42", Unstable(sym::nvptx_target_feature), &["ptx41"]), - ("ptx43", Unstable(sym::nvptx_target_feature), &["ptx42"]), - ("ptx50", Unstable(sym::nvptx_target_feature), &["ptx43"]), - ("ptx60", Unstable(sym::nvptx_target_feature), &["ptx50"]), - ("ptx61", Unstable(sym::nvptx_target_feature), &["ptx60"]), - ("ptx62", Unstable(sym::nvptx_target_feature), &["ptx61"]), - ("ptx63", Unstable(sym::nvptx_target_feature), &["ptx62"]), - ("ptx64", Unstable(sym::nvptx_target_feature), &["ptx63"]), - ("ptx65", Unstable(sym::nvptx_target_feature), &["ptx64"]), - ("ptx70", Unstable(sym::nvptx_target_feature), &["ptx65"]), + ("ptx70", Unstable(sym::nvptx_target_feature), &[]), ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]), ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]), ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]), diff --git a/library/core/src/field.rs b/library/core/src/field.rs index 120d7a9f4760c..90d16e5f2af5f 100644 --- a/library/core/src/field.rs +++ b/library/core/src/field.rs @@ -1,11 +1,12 @@ //! Field Reflection +use crate::fmt; +use crate::hash::{Hash, Hasher}; use crate::marker::PhantomData; /// Field Representing Type #[unstable(feature = "field_representing_type_raw", issue = "none")] #[lang = "field_representing_type"] -#[expect(missing_debug_implementations)] #[fundamental] pub struct FieldRepresentingType { // We want this type to be invariant over `T`, because otherwise `field_of!(Struct<'short>, @@ -14,16 +15,50 @@ pub struct FieldRepresentingType T>, } -// SAFETY: `FieldRepresentingType` doesn't contain any `T` -unsafe impl Send - for FieldRepresentingType -{ -} - -// SAFETY: `FieldRepresentingType` doesn't contain any `T` -unsafe impl Sync +impl fmt::Debug for FieldRepresentingType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + enum Member { + Name(&'static str), + Index(u32), + } + impl fmt::Display for Member { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Name(name) => fmt::Display::fmt(name, f), + Self::Index(idx) => fmt::Display::fmt(idx, f), + } + } + } + let (variant, field) = const { + use crate::mem::type_info::{Type, TypeKind}; + match Type::of::().kind { + TypeKind::Struct(struct_) => { + (None, Member::Name(struct_.fields[FIELD as usize].name)) + } + TypeKind::Tuple(_) => (None, Member::Index(FIELD)), + TypeKind::Enum(enum_) => { + let variant = &enum_.variants[VARIANT as usize]; + (Some(variant.name), Member::Name(variant.fields[FIELD as usize].name)) + } + TypeKind::Union(union) => (None, Member::Name(union.fields[FIELD as usize].name)), + _ => unreachable!(), + } + }; + let type_name = const { crate::any::type_name::() }; + match variant { + Some(variant) => write!(f, "field_of!({type_name}, {variant}.{field})"), + None => write!(f, "field_of!({type_name}, {field})"), + } + // NOTE: if there are changes in the reflection work and the above no + // longer compiles, then the following debug impl could also work in + // the meantime: + // ```rust + // let type_name = const { type_name::() }; + // write!(f, "field_of!({type_name}, {VARIANT}.{FIELD})") + // ``` + } } impl Copy @@ -39,6 +74,51 @@ impl Clone } } +impl Default + for FieldRepresentingType +{ + fn default() -> Self { + Self { _phantom: PhantomData::default() } + } +} + +impl Hash + for FieldRepresentingType +{ + fn hash(&self, state: &mut H) { + self._phantom.hash(state); + } +} + +impl PartialEq + for FieldRepresentingType +{ + fn eq(&self, other: &Self) -> bool { + self._phantom == other._phantom + } +} + +impl Eq + for FieldRepresentingType +{ +} + +impl PartialOrd + for FieldRepresentingType +{ + fn partial_cmp(&self, other: &Self) -> Option { + self._phantom.partial_cmp(&other._phantom) + } +} + +impl Ord + for FieldRepresentingType +{ + fn cmp(&self, other: &Self) -> crate::cmp::Ordering { + self._phantom.cmp(&other._phantom) + } +} + /// Expands to the field representing type of the given field. /// /// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 934d4bd684034..f79a93214ea2c 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -3098,9 +3098,7 @@ impl Read for Take { let is_init = buf.is_init(); // SAFETY: no uninit data is written to ibuf - let ibuf = unsafe { &mut buf.as_mut()[..limit] }; - - let mut sliced_buf: BorrowedBuf<'_> = ibuf.into(); + let mut sliced_buf = BorrowedBuf::from(unsafe { &mut buf.as_mut()[..limit] }); if is_init { // SAFETY: `sliced_buf` is a subslice of `buf`, so if `buf` was initialized then @@ -3108,22 +3106,23 @@ impl Read for Take { unsafe { sliced_buf.set_init() }; } - let mut cursor = sliced_buf.unfilled(); - let result = self.inner.read_buf(cursor.reborrow()); + let result = self.inner.read_buf(sliced_buf.unfilled()); - let should_init = cursor.is_init(); + let did_init_up_to_limit = sliced_buf.is_init(); let filled = sliced_buf.len(); - // cursor / sliced_buf / ibuf must drop here + // sliced_buf must drop here // Avoid accidentally quadratic behaviour by initializing the whole // cursor if only part of it was initialized. - if should_init { - // SAFETY: no uninit data is written - let uninit = unsafe { &mut buf.as_mut()[limit..] }; - uninit.write_filled(0); - // SAFETY: all bytes that were not initialized by `T::read_buf` - // have just been written to. + if did_init_up_to_limit && !is_init { + // SAFETY: No uninit data will be written. + let unfilled_before_advance = unsafe { buf.as_mut() }; + + unfilled_before_advance[limit..].write_filled(0); + + // SAFETY: `unfilled_before_advance[..limit]` was initialized by `T::read_buf`, and + // `unfilled_before_advance[limit..]` was just initialized. unsafe { buf.set_init() }; } diff --git a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md index dbdb96283a5fa..8934e7085b8d7 100644 --- a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md +++ b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md @@ -59,11 +59,6 @@ Build the library as `cdylib`: # Cargo.toml [lib] crate-type = ["cdylib"] - -[profile.dev] -lto = true # LTO must be explicitly enabled for now -[profile.release] -lto = true ``` The target-cpu must be from the list [supported by LLVM] (or printed with `rustc --target amdgcn-amd-amdhsa --print target-cpus`). diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md index 2d9fc85dad33d..02510d9f3dee2 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -25,13 +25,23 @@ There are two options for using the core library: ### Target and features -It is generally necessary to specify the target, such as `-C target-cpu=sm_89`, because the default is very old. This implies two target features: `sm_89` and `ptx78` (and all preceding features within `sm_*` and `ptx*`). Rust will default to using the oldest PTX version that supports the target processor (see [this table](https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#release-notes-ptx-release-history)), which maximizes driver compatibility. -One can use `-C target-feature=+ptx80` to choose a later PTX version without changing the target (the default in this case, `ptx78`, requires CUDA driver version 11.8, while `ptx80` would require driver version 12.0). +It is often beneficial to specify the target SM architecture, such as `-C target-cpu=sm_89`, because the default prioritizes broad compatibility rather than performance. Doing so also selects the PTX version as the *maximum* of (a) the oldest PTX version that supports the chosen target processor (see [this table](https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#release-notes-ptx-release-history)) and (b) the oldest PTX version supported by the Rust toolchain, which maximizes driver compatibility. +One can use `-C target-feature=+ptx80` to choose a later PTX version without changing the target SM architecture (the default in this case, `ptx78`, requires CUDA driver version 11.8, while `ptx80` would require driver version 12.0). Later PTX versions may allow more efficient code generation. Although Rust follows LLVM in representing `ptx*` and `sm_*` as target features, they should be thought of as having crate granularity, set via (either via `-Ctarget-cpu` and optionally `-Ctarget-feature`). While the compiler accepts `#[target_feature(enable = "ptx80", enable = "sm_89")]`, it is not supported, may not behave as intended, and may become erroneous in the future. +## Minimum SM and PTX support by Rust version +Support for old hardware architectures and PTX ISA versions is periodically dropped. This table shows the minimum supported versions per Rust version. + +| Rust | SM minimum | PTX ISA minimum | +| ------------ | -------------- | --------------- | +| - 1.96 | 2.0 | 3.2 | +| 1.97 - TBD | 7.0 (Volta+) | 7.0 (CUDA 11+) | + +For a full overview of which GPUs support code built for a specific SM version, see the [CUDA GPU Compute Capability documentation](https://developer.nvidia.com/cuda/gpus). + ## Building Rust kernels A `no_std` crate containing one or more functions with `extern "ptx-kernel"` can be compiled to PTX using a command like the following. diff --git a/tests/assembly-llvm/nvptx-arch-default.rs b/tests/assembly-llvm/nvptx-arch-default.rs index 22b4a680e322c..e71304e453303 100644 --- a/tests/assembly-llvm/nvptx-arch-default.rs +++ b/tests/assembly-llvm/nvptx-arch-default.rs @@ -8,5 +8,6 @@ extern crate breakpoint_panic_handler; // Verify default target arch with ptx-linker. -// CHECK: .target sm_30 +// CHECK: .version 7.0 +// CHECK: .target sm_70 // CHECK: .address_size 64 diff --git a/tests/assembly-llvm/nvptx-arch-emit-asm.rs b/tests/assembly-llvm/nvptx-arch-emit-asm.rs index e47f8e78e3679..9266309c6202e 100644 --- a/tests/assembly-llvm/nvptx-arch-emit-asm.rs +++ b/tests/assembly-llvm/nvptx-arch-emit-asm.rs @@ -5,5 +5,6 @@ #![no_std] // Verify default arch without ptx-linker involved. -// CHECK: .target sm_30 +// CHECK: .version 7.0 +// CHECK: .target sm_70 // CHECK: .address_size 64 diff --git a/tests/run-make-cargo/amdgpu-lto/Cargo.toml b/tests/run-make-cargo/amdgpu-lto/Cargo.toml new file mode 100644 index 0000000000000..b2607b747fd7f --- /dev/null +++ b/tests/run-make-cargo/amdgpu-lto/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "amdgpu_lto" +version = "0.1.0" +edition = "2024" + +[lib] +path = "lib.rs" +crate-type = ["cdylib"] diff --git a/tests/run-make-cargo/amdgpu-lto/lib.rs b/tests/run-make-cargo/amdgpu-lto/lib.rs new file mode 100644 index 0000000000000..d17cf5a8316ca --- /dev/null +++ b/tests/run-make-cargo/amdgpu-lto/lib.rs @@ -0,0 +1,15 @@ +#![feature(abi_gpu_kernel)] +#![no_std] + +#[panic_handler] +fn panic_handler(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[unsafe(no_mangle)] +fn foo(a: i32, b: i32) -> i32 { + a + b +} + +#[unsafe(no_mangle)] +extern "gpu-kernel" fn kernel() {} diff --git a/tests/run-make-cargo/amdgpu-lto/rmake.rs b/tests/run-make-cargo/amdgpu-lto/rmake.rs new file mode 100644 index 0000000000000..cb3dc81f34d15 --- /dev/null +++ b/tests/run-make-cargo/amdgpu-lto/rmake.rs @@ -0,0 +1,28 @@ +// Check that compiling for the amdgpu target which needs LTO works with a default +// cargo configuration. + +//@ needs-llvm-components: amdgpu +//@ needs-rust-lld + +#![deny(warnings)] + +use run_make_support::{cargo, path}; + +fn main() { + let target_dir = path("target"); + + cargo() + .args(&[ + "build", + "--release", + "--lib", + "--manifest-path", + "Cargo.toml", + "-Zbuild-std=core", + "--target", + "amdgcn-amd-amdhsa", + ]) + .env("RUSTFLAGS", "-Ctarget-cpu=gfx900") + .env("CARGO_TARGET_DIR", &target_dir) + .run(); +} diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index b53419c512b08..981c173242408 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -229,18 +229,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `power9-altivec` `power9-vector` `prfchw` -`ptx32` -`ptx40` -`ptx41` -`ptx42` -`ptx43` -`ptx50` -`ptx60` -`ptx61` -`ptx62` -`ptx63` -`ptx64` -`ptx65` `ptx70` `ptx71` `ptx72` @@ -290,18 +278,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `sm_101a` `sm_120` `sm_120a` -`sm_20` -`sm_21` -`sm_30` -`sm_32` -`sm_35` -`sm_37` -`sm_50` -`sm_52` -`sm_53` -`sm_60` -`sm_61` -`sm_62` `sm_70` `sm_72` `sm_75` diff --git a/tests/ui/closures/closure-return-block-note-issue-155670.rs b/tests/ui/closures/closure-return-block-note-issue-155670.rs new file mode 100644 index 0000000000000..fccce9ee54ca2 --- /dev/null +++ b/tests/ui/closures/closure-return-block-note-issue-155670.rs @@ -0,0 +1,14 @@ +struct SmolStr; + +const _: fn() = || { + match Some(()) { + Some(()) => (), + None => return, + }; + let _: String = { + SmolStr + //~^ ERROR mismatched types + }; +}; + +fn main() {} diff --git a/tests/ui/closures/closure-return-block-note-issue-155670.stderr b/tests/ui/closures/closure-return-block-note-issue-155670.stderr new file mode 100644 index 0000000000000..f38d2f14200d4 --- /dev/null +++ b/tests/ui/closures/closure-return-block-note-issue-155670.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/closure-return-block-note-issue-155670.rs:9:9 + | +LL | SmolStr + | ^^^^^^^ expected `String`, found `SmolStr` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/field_representing_types/not-field-if-unsized.next.stderr b/tests/ui/field_representing_types/not-field-if-unsized.next.stderr new file mode 100644 index 0000000000000..e3cee80907720 --- /dev/null +++ b/tests/ui/field_representing_types/not-field-if-unsized.next.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied + --> $DIR/not-field-if-unsized.rs:17:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)` + | +note: required by a bound in `assert_field` + --> $DIR/not-field-if-unsized.rs:12:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error[E0277]: the trait bound `field_of!(MyStruct, 1): std::field::Field` is not satisfied + --> $DIR/not-field-if-unsized.rs:21:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 1)` + | +note: required by a bound in `assert_field` + --> $DIR/not-field-if-unsized.rs:12:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/field_representing_types/not-field-if-unsized.old.stderr b/tests/ui/field_representing_types/not-field-if-unsized.old.stderr new file mode 100644 index 0000000000000..e3cee80907720 --- /dev/null +++ b/tests/ui/field_representing_types/not-field-if-unsized.old.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied + --> $DIR/not-field-if-unsized.rs:17:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)` + | +note: required by a bound in `assert_field` + --> $DIR/not-field-if-unsized.rs:12:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error[E0277]: the trait bound `field_of!(MyStruct, 1): std::field::Field` is not satisfied + --> $DIR/not-field-if-unsized.rs:21:20 + | +LL | assert_field::(); + | ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 1)` + | +note: required by a bound in `assert_field` + --> $DIR/not-field-if-unsized.rs:12:20 + | +LL | fn assert_field() {} + | ^^^^^ required by this bound in `assert_field` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/field_representing_types/not-field-if-unsized.rs b/tests/ui/field_representing_types/not-field-if-unsized.rs new file mode 100644 index 0000000000000..739fc91c29423 --- /dev/null +++ b/tests/ui/field_representing_types/not-field-if-unsized.rs @@ -0,0 +1,23 @@ +//@ revisions: old next +//@ [next] compile-flags: -Znext-solver +#![expect(incomplete_features)] +#![feature(field_projections)] + +use std::field::{Field, field_of}; + +pub trait Trait {} + +pub struct MyStruct(usize, dyn Trait); + +fn assert_field() {} + +fn main() { + // FIXME(FRTs): this requires relaxing the `Base: ?Sized` bound in the + // `Field` trait & compiler changes. + assert_field::(); + //~^ ERROR: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied [E0277] + + // FIXME(FRTs): improve this error message, point to the `dyn Trait` span. + assert_field::(); + //~^ ERROR: the trait bound `field_of!(MyStruct, 1): std::field::Field` is not satisfied [E0277] +} diff --git a/tests/ui/field_representing_types/traits.rs b/tests/ui/field_representing_types/traits.rs index 6b5bb15f9ee9a..bc31376e60ea2 100644 --- a/tests/ui/field_representing_types/traits.rs +++ b/tests/ui/field_representing_types/traits.rs @@ -1,13 +1,17 @@ //@ revisions: old next //@ [next] compile-flags: -Znext-solver //@ run-pass -#![feature(field_projections, freeze)] +#![feature(field_projections, freeze, unsafe_unpin)] #![expect(incomplete_features, dead_code)] use std::field::field_of; -use std::marker::{Freeze, Unpin}; +use std::fmt::Debug; +use std::hash::Hash; +use std::marker::{Freeze, Unpin, UnsafeUnpin}; +use std::panic::{RefUnwindSafe, UnwindSafe}; struct Struct { field: u32, + tail: [u32], } union Union { @@ -19,11 +23,37 @@ enum Enum { Variant2(u32), } -fn assert_traits() {} +type Tuple = ((), usize, String, dyn Debug); + +fn assert_traits< + T: Sized + + Freeze + + RefUnwindSafe + + Send + + Sync + + Unpin + + UnsafeUnpin + + UnwindSafe + + Copy + + Debug + + Default + + Eq + + Hash + + Ord, +>() { +} fn main() { assert_traits::(); + assert_traits::(); + assert_traits::(); + assert_traits::(); assert_traits::(); + + assert_traits::(); + assert_traits::(); + assert_traits::(); + assert_traits::(); } diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr index 2447a5d8d4b80..bba17eb2494e2 100644 --- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-impl-trait.stderr @@ -21,6 +21,18 @@ LL | return A; LL | } LL | B | ^ expected `A`, found `B` + | +help: you could change the return type to be a boxed trait object + | +LL - fn cat() -> impl DynCompatible { +LL + fn cat() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ return Box::new(A); +LL | } +LL ~ Box::new(B) + | error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr index 2a4c5ff4a5bed..13a78cb0fcf35 100644 --- a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr @@ -72,6 +72,17 @@ LL | } LL | 1u32 | ^^^^ expected `i32`, found `u32` | +help: you could change the return type to be a boxed trait object + | +LL - fn foo() -> impl std::fmt::Display { +LL + fn foo() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ return Box::new(0i32); +LL | } +LL ~ Box::new(1u32) + | help: change the type of the numeric literal from `u32` to `i32` | LL - 1u32 @@ -90,6 +101,17 @@ LL | } else { LL | return 1u32; | ^^^^ expected `i32`, found `u32` | +help: you could change the return type to be a boxed trait object + | +LL - fn bar() -> impl std::fmt::Display { +LL + fn bar() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ return Box::new(0i32); +LL | } else { +LL ~ return Box::new(1u32); + | help: change the type of the numeric literal from `u32` to `i32` | LL - return 1u32; @@ -108,6 +130,17 @@ LL | } else { LL | 1u32 | ^^^^ expected `i32`, found `u32` | +help: you could change the return type to be a boxed trait object + | +LL - fn baz() -> impl std::fmt::Display { +LL + fn baz() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ return Box::new(0i32); +LL | } else { +LL ~ Box::new(1u32) + | help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | }.try_into().unwrap() @@ -153,6 +186,16 @@ LL | 0 => return 0i32, LL | _ => 1u32, | ^^^^ expected `i32`, found `u32` | +help: you could change the return type to be a boxed trait object + | +LL - fn bat() -> impl std::fmt::Display { +LL + fn bat() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ 0 => return Box::new(0i32), +LL ~ _ => Box::new(1u32), + | help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | }.try_into().unwrap() @@ -171,6 +214,17 @@ LL | | _ => 2u32, LL | | } | |_____^ expected `i32`, found `u32` | +help: you could change the return type to be a boxed trait object + | +LL - fn can() -> impl std::fmt::Display { +LL + fn can() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ 0 => return Box::new(0i32), +LL ~ 1 => Box::new(1u32), +LL ~ _ => Box::new(2u32), + | help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | }.try_into().unwrap() @@ -188,6 +242,18 @@ LL | return 0i32; LL | 1u32 | ^^^^ expected `i32`, found `u32` | +help: you could change the return type to be a boxed trait object + | +LL - fn cat() -> impl std::fmt::Display { +LL + fn cat() -> Box { + | +help: if you change the return type to expect trait objects, box the returned expressions + | +LL ~ return Box::new(0i32); +LL | } +LL | _ => { +LL ~ Box::new(1u32) + | help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | }.try_into().unwrap() diff --git a/tests/ui/target-cpu/unsupported-target-cpu.nvptx-sm60.stderr b/tests/ui/target-cpu/unsupported-target-cpu.nvptx-sm60.stderr new file mode 100644 index 0000000000000..76092b8391f33 --- /dev/null +++ b/tests/ui/target-cpu/unsupported-target-cpu.nvptx-sm60.stderr @@ -0,0 +1,4 @@ +error: target cpu `sm_60` is known but unsupported + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-cpu/unsupported-target-cpu.rs b/tests/ui/target-cpu/unsupported-target-cpu.rs new file mode 100644 index 0000000000000..dafbfbc015ec1 --- /dev/null +++ b/tests/ui/target-cpu/unsupported-target-cpu.rs @@ -0,0 +1,14 @@ +//! Check that certain target *respect* the unsupported-cpus in `-C target-cpu`. + +//@ revisions: nvptx-sm60 + +//@[nvptx-sm60] compile-flags: --target=nvptx64-nvidia-cuda --crate-type=rlib -Ctarget-cpu=sm_60 +//@[nvptx-sm60] needs-llvm-components: nvptx +//@[nvptx-sm60] build-fail +//@ ignore-backends: gcc + +#![feature(no_core)] +#![no_core] +#![crate_type = "rlib"] + +//[nvptx-sm60]~? ERROR target cpu `sm_60` is known but unsupported