diff --git a/Cargo.lock b/Cargo.lock index 986e55fa991ca..feeba051664e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5177,7 +5177,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.11.0" +version = "1.12.0" dependencies = [ "annotate-snippets 0.12.16", "anyhow", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5ccf0eaf02bd4..b5d8614804812 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1779,7 +1779,7 @@ pub enum ExprKind { Lit(token::Lit), /// A cast (e.g., `foo as f64`). Cast(Box, Box), - /// A type ascription (e.g., `builtin # type_ascribe(42, usize)`). + /// A type ascription (e.g., `k#type_ascribe(42, usize)`). /// /// Usually not written directly in user code but /// indirectly via the macro `type_ascribe!(...)`. @@ -1871,7 +1871,7 @@ pub enum ExprKind { /// Output of the `asm!()` macro. InlineAsm(Box), - /// An `offset_of` expression (e.g., `builtin # offset_of(Struct, field)`). + /// An `offset_of` expression (e.g., `k#offset_of(Struct, field)`). /// /// Usually not written directly in user code but /// indirectly via the macro `core::mem::offset_of!(...)`. @@ -2570,7 +2570,7 @@ pub enum TyKind { /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero`, /// just as part of the type system. Pat(Box, Box), - /// A `field_of` expression (e.g., `builtin # field_of(Struct, field)`). + /// A `field_of` expression (e.g., `k#field_of(Struct, field)`). /// /// Usually not written directly in user code but indirectly via the macro /// `core::field::field_of!(...)`. diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 20079dd039f6f..4ec5fe2a8bd84 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -313,6 +313,8 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, kind: IdentKind) -> bool { // WARNING: Take care when modifying this function! It will change the stable(!) set of // tokens that are allowed to match an `expr` nonterminal which is user observable. + // NOTE: We don't care about forced keywords that are gated behind `internal_syntax`. + let ident_token = Token::new(Ident(name, kind), span); // FIXME: Remove `box` from this list given we officially no longer support box expressions @@ -350,6 +352,8 @@ fn ident_can_begin_type(name: Symbol, span: Span, kind: IdentKind) -> bool { // WARNING: Take care when modifying this function! It will change the stable(!) set of // tokens that are allowed to match an `ty` nonterminal which is user observable. + // NOTE: We don't care about forced keywords that are gated behind `internal_syntax`. + let ident_token = Token::new(Ident(name, kind), span); !ident_token.is_reserved_ident() @@ -936,6 +940,10 @@ impl Token { self.non_raw_ident().is_some_and(|id| id.name == kw) } + pub fn is_forced_keyword(&self, kw: Symbol) -> bool { + self.ident().is_some_and(|(id, kind)| kind == IdentKind::ForcedKeyword && id.name == kw) + } + /// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this /// token is an identifier equal to `kw` ignoring the case. pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index bc0604cf96e95..862d4736ca33c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -431,7 +431,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { // tidy-alphabetical-start gate_all!(async_for_loop, "`for await` loops are experimental"); - gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); gate_all!(const_block_items, "const block items are experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); @@ -452,6 +451,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(global_registration, "global registration is experimental"); gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards"); gate_all!(impl_restriction, "`impl` restrictions are experimental"); + gate_all!(internal_syntax, "this syntax is internal"); gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); gate_all!(move_expr, "`move(expr)` syntax is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a082300bb47ed..a5dbaf81376c1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1442,7 +1442,7 @@ impl<'a> State<'a> { self.print_ty_pat(pat); } ast::TyKind::FieldOf(ty, variant, field) => { - self.word("builtin # field_of"); + self.word("k#field_of"); self.popen(); let ib = self.ibox(0); self.print_type(ty); @@ -2012,6 +2012,11 @@ impl<'a> State<'a> { self.pclose(); } PatKind::Deref(inner) => { + // FIXME(deref_patterns, internal_syntax, forced_keywords, clippy): + // This should render `k#deref(...)` but unfortunately Clippy uses `pat_to_string` + // for the suggestions of its lint `unnested_or_patterns`. Smh fix Clippy to not + // rely on AST pretty printing `deref!(…)` for `Deref` patterns and please don't + // think about adding a flag to AST pretty to control the output. self.word("deref!"); self.popen(); self.print_pat(inner); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index d6e8f69dbfa03..51e3988577827 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -497,7 +497,7 @@ impl<'a> State<'a> { self.print_type(ty); } ast::ExprKind::Type(expr, ty) => { - self.word("builtin # type_ascribe"); + self.word("k#type_ascribe"); self.popen(); let ib = self.ibox(0); self.print_expr(expr, FixupContext::default()); @@ -777,12 +777,12 @@ impl<'a> State<'a> { self.print_expr(result, fixup.rightmost_subexpression()); } ast::ExprKind::InlineAsm(a) => { - // FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`. + // FIXME: Print `k#asm` once macro `asm` uses `internal_syntax`. self.word(format!("{}!", a.asm_macro.macro_name())); self.print_inline_asm(a); } ast::ExprKind::FormatArgs(fmt) => { - // FIXME: Print `builtin # format_args` once macro `format_args` uses `builtin_syntax`. + // FIXME: Print `k#format_args` once macro `format_args` uses `internal_syntax`. self.word("format_args!"); self.popen(); let ib = self.ibox(0); @@ -795,7 +795,7 @@ impl<'a> State<'a> { self.pclose(); } ast::ExprKind::OffsetOf(container, fields) => { - self.word("builtin # offset_of"); + self.word("k#offset_of"); self.popen(); let ib = self.ibox(0); self.print_type(container); @@ -855,10 +855,9 @@ impl<'a> State<'a> { self.print_block_with_attrs(blk, attrs, cb, ib) } ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => { - self.word("builtin # "); match kind { - ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"), - ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"), + ast::UnsafeBinderCastKind::Wrap => self.word("k#wrap_binder"), + ast::UnsafeBinderCastKind::Unwrap => self.word("k#unwrap_binder"), } self.popen(); let ib = self.ibox(0); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6ce34cecc7e97..84d620b9b5250 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -288,7 +288,7 @@ impl<'a> State<'a> { self.bclose(item.span, empty, cb); } ast::ItemKind::GlobalAsm(asm) => { - // FIXME: Print `builtin # global_asm` once macro `global_asm` uses `builtin_syntax`. + // FIXME: Print `k#global_asm` once macro `global_asm` uses `internal_syntax`. let (cb, ib) = self.head(visibility_qualified(&item.vis, "global_asm!")); self.print_inline_asm(asm); self.word(";"); diff --git a/compiler/rustc_attr_ir/src/lang_items.rs b/compiler/rustc_attr_ir/src/lang_items.rs index d715a6d3af8c5..56fb1a4b6c865 100644 --- a/compiler/rustc_attr_ir/src/lang_items.rs +++ b/compiler/rustc_attr_ir/src/lang_items.rs @@ -163,7 +163,7 @@ language_item_table! { Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); AlignOf, sym::mem_align_const, align_const, Target::AssocConst(AssocCtxt::Trait), GenericRequirement::Exact(0); SizeOf, sym::mem_size_const, size_const, Target::AssocConst(AssocCtxt::Trait), GenericRequirement::Exact(0); - OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1); + OffsetOf, kw::OffsetOf, offset_of, Target::Fn, GenericRequirement::Exact(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); @@ -239,7 +239,7 @@ language_item_table! { Complex, sym::complex, complex, Target::Struct, GenericRequirement::Exact(1); PpcF128, sym::ppcf128, ppcf128, Target::Struct, GenericRequirement::None; - Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); + Deref, kw::Deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0); DerefTarget, sym::deref_target, deref_target, Target::AssocTy(AssocCtxt::Trait), GenericRequirement::None; diff --git a/compiler/rustc_attr_parsing/src/attributes/lint.rs b/compiler/rustc_attr_parsing/src/attributes/lint.rs index e0607c49124d9..938de1a8597ab 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint.rs @@ -8,6 +8,7 @@ use thin_vec::ThinVec; use crate::attributes::{AcceptMapping, AttributeParser, AttributeStability}; use crate::context::{AcceptContext, ExpectStringLiteral, FinalizeContext}; +use crate::diagnostics::{MalformedLintAttributeInput, MalformedLintAttributeInputHelp}; use crate::parser::{ArgParser, MetaItemOrLitParser}; use crate::target_checking::AllowedTargets; use crate::target_checking::Policy::{Allow, Warn}; @@ -36,9 +37,11 @@ impl LintParser { let p = parsers.last()?.meta_item()?; let nv = p.args().as_name_value()?; if !p.path().word_is(sym::reason) { - cx.emit_err(diagnostics::MalformedAttribute { + // FIXME: We should recommend `reason` here + cx.emit_err(MalformedLintAttributeInput { span: p.span(), - kind: diagnostics::MalformedAttributeKind::BadAttributeArgument(p.span()), + help: MalformedLintAttributeInputHelp::Other { kind: kind.sym() }, + kind: kind.sym(), }); } else { parsers = &parsers[..(parsers.len() - 1)]; @@ -78,26 +81,28 @@ impl LintParser { nv.expect_string_literal(cx); } ArgParser::NameValue(_) | ArgParser::List(_) => { - cx.emit_err(diagnostics::MalformedAttribute { + cx.emit_err(MalformedLintAttributeInput { span: p.span(), - kind: diagnostics::MalformedAttributeKind::BadAttributeArgument( - item.span(), - ), + help: MalformedLintAttributeInputHelp::Other { + kind: kind.sym(), + }, + kind: kind.sym(), }); } } } MetaItemOrLitParser::Lit(lit) => { - cx.emit_err(diagnostics::BadAttributeLit { + cx.emit_err(MalformedLintAttributeInput { span: item.span(), help: if lit.kind.is_str() { - diagnostics::BadAttributeLitHelp::StrLit { + MalformedLintAttributeInputHelp::StrLit { sym: lit.symbol, kind: kind.sym(), } } else { - diagnostics::BadAttributeLitHelp::Other { kind: kind.sym() } + MalformedLintAttributeInputHelp::Other { kind: kind.sym() } }, + kind: kind.sym(), }); } } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 127b0e4f14de8..d33c52fb061c8 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -2196,24 +2196,23 @@ pub(crate) struct MalformedAttribute { #[derive(Subdiagnostic)] pub(crate) enum MalformedAttributeKind { - #[label("bad attribute argument")] - BadAttributeArgument(#[primary_span] Span), #[label("reason in lint attribute must come last")] ReasonMustComeLast(#[primary_span] Span), } #[derive(Diagnostic)] -#[diag("expected a lint, found literal")] -pub(crate) struct BadAttributeLit { +#[diag("malformed `{$kind}` attribute input")] +pub(crate) struct MalformedLintAttributeInput { #[primary_span] #[label("not the name of a lint")] pub span: Span, + pub kind: Symbol, #[subdiagnostic] - pub help: BadAttributeLitHelp, + pub help: MalformedLintAttributeInputHelp, } #[derive(Subdiagnostic)] -pub(crate) enum BadAttributeLitHelp { +pub(crate) enum MalformedLintAttributeInputHelp { #[help("try using `#[{$kind}({$sym})]`")] StrLit { sym: Symbol, kind: Symbol }, #[help("for example, write `#[{$kind}(dead_code)]` for `dead_code`")] diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b8237443cccc3..7e71755ed4e70 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -657,22 +657,17 @@ pub(crate) unsafe fn llvm_optimize<'ll>( None }; - fn handle_offload<'ll>(cx: &SimpleCx<'ll>, old_fn: &'ll llvm::Value) { + // Wraps `old_fn` into a new kernel that takes the implicit `dyn_ptr` as its first argument. + // Returns the new function, or `None` if nothing was wrapped + fn handle_offload<'ll>( + cx: &SimpleCx<'ll>, + old_fn: &'ll llvm::Value, + ) -> Option<&'ll llvm::Value> { let old_fn_ty = cx.get_type_of_global(old_fn); let old_param_types = cx.func_params_types(old_fn_ty); let old_param_count = old_param_types.len(); if old_param_count == 0 { - return; - } - - let first_param = llvm::get_param(old_fn, 0); - let c_name = llvm::get_value_name(first_param); - let first_arg_name = str::from_utf8(&c_name).unwrap(); - // We might call llvm_optimize (and thus this code) multiple times on the same IR, - // but we shouldn't add this helper ptr multiple times. - // FIXME(offload): This could break if the user calls his first argument `dyn_ptr`. - if first_arg_name == "dyn_ptr" { - return; + return None; } // Create the new parameter list, with ptr as the first argument @@ -747,6 +742,7 @@ pub(crate) unsafe fn llvm_optimize<'ll>( } // Now we can re-use the old name, without name collision. llvm::set_value_name(new_fn, &name); + Some(new_fn) } if cgcx.target_is_like_gpu @@ -755,10 +751,13 @@ pub(crate) unsafe fn llvm_optimize<'ll>( let cx = SimpleCx::new(llmod, llcx, cgcx.pointer_size); for func in cx.get_functions() { let offload_kernel = "offload-kernel"; - if attributes::has_string_attr(func, offload_kernel) { - handle_offload(&cx, func); + if !attributes::has_string_attr(func, offload_kernel) { + continue; + } + match handle_offload(&cx, func) { + Some(new_fn) => attributes::remove_string_attr_from_llfn(new_fn, offload_kernel), + None => attributes::remove_string_attr_from_llfn(func, offload_kernel), } - attributes::remove_string_attr_from_llfn(func, offload_kernel); } } @@ -822,8 +821,9 @@ pub(crate) unsafe fn llvm_optimize<'ll>( }; // This assumes that we previously compiled our kernels for a gpu target, which created a - // `.bc` artifact. The user is supposed to provide us with a path to this artifact, we - // don't need any other artifacts from the previous run. + // `.ptx` (NVPTX) or `.elf` (AMDGPU) artifact. + // The user is supposed to provide us with a path to this artifact, + // we don't need any other artifacts from the previous run. if !cgcx.target_is_like_gpu && is_final_stage { if let Some(device_path) = config .offload @@ -833,15 +833,18 @@ pub(crate) unsafe fn llvm_optimize<'ll>( let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { dcx.emit_err(crate::diagnostics::OffloadWithoutAbsPath); - } else if device_pathbuf.extension().and_then(|e| e.to_str()) != Some("bc") { + } else if !matches!( + device_pathbuf.extension().and_then(|e| e.to_str()), + Some("ptx" | "elf") + ) { dcx.emit_err(crate::diagnostics::OffloadWrongFileName); } else if !device_pathbuf.exists() { dcx.emit_err(crate::diagnostics::OffloadNonexistingPath); } - let device_bitcode_c = path_to_c_string(device_pathbuf.as_path()); + let device_image_c = path_to_c_string(device_pathbuf.as_path()); let ok = unsafe { llvm::RustOffloadWrapper::get_instance() - .llvm_rust_offload_wrap_images(llmod, device_bitcode_c.as_c_str()) + .llvm_rust_offload_wrap_images(llmod, device_image_c.as_c_str()) }; if !ok { dcx.emit_err(crate::diagnostics::OffloadWrapImagesFailed); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 2089f2b2008be..30b8b3682c3b1 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -22,7 +22,6 @@ use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; use crate::diagnostics::SymbolAlreadyDefined; use crate::llvm::{self, Type, Value, const_ptr_auth}; -use crate::type_of::LayoutLlvmExt; use crate::{base, debuginfo}; /// Indicates whether a value originates from a `static`. @@ -200,7 +199,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( let mut should_sign = false; // Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare // an extern_weak function, otherwise a global with the desired linkage. - let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) { + let actual_global = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) { // An `extern_weak` function is represented as an `Option`, // we extract the function signature and declare it as an extern_weak function // instead of an extern_weak i8. @@ -224,28 +223,11 @@ fn check_and_apply_linkage<'ll, 'tcx>( } else { cx.declare_global(sym, cx.type_i8()) }; - llvm::set_linkage(g1, base::linkage_to_llvm(linkage)); + llvm::set_linkage(actual_global, base::linkage_to_llvm(linkage)); // Normally this is done in `get_static_inner`, but when as we generate an internal global, // it will apply the dso_local to the internal global instead, so do it here, too. - cx.assume_dso_local(g1, true); - - // Declare an internal global `extern_with_linkage_foo` which - // is initialized with the address of `foo`. If `foo` is - // discarded during linking (for example, if `foo` has weak - // linkage and there are no definitions), then - // `extern_with_linkage_foo` will instead be initialized to - // zero. - let real_name = - format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE)); - let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { - cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { - span: cx.tcx.def_span(def_id), - symbol_name: sym, - }) - }); - llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); - llvm::set_unnamed_address(g2, llvm::UnnamedAddr::Global); + cx.assume_dso_local(actual_global, true); // Sign the function pointer that is used to initialize the global let initializer = if should_sign { @@ -256,18 +238,36 @@ fn check_and_apply_linkage<'ll, 'tcx>( .expect("pointer authentication functions must be available when signing"); const_ptr_auth( - cx.const_bitcast(g1, llty), + actual_global, schema.key as u32, schema.constant_discriminator as u64, None, /* address_diversity */ ) } else { - g1 + actual_global }; - llvm::set_initializer(g2, initializer); - - g2 + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let real_name = + format!("_rust_extern_with_linkage_{:016x}_{sym}", cx.tcx.stable_crate_id(LOCAL_CRATE)); + let pointer_global = + cx.define_global(&real_name, cx.val_ty(initializer)).unwrap_or_else(|| { + cx.sess().dcx().emit_fatal(SymbolAlreadyDefined { + span: cx.tcx.def_span(def_id), + symbol_name: sym, + }) + }); + llvm::set_linkage(pointer_global, llvm::Linkage::InternalLinkage); + llvm::set_unnamed_address(pointer_global, llvm::UnnamedAddr::Global); + + llvm::set_initializer(pointer_global, initializer); + + pointer_global } else if cx.tcx.sess.target.arch == Arch::X86 && common::is_using_dlltool(&cx.tcx.sess.target) && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym) @@ -358,7 +358,7 @@ impl<'ll> CodegenCx<'ll, '_> { } else { let ty = instance.ty(self.tcx, self.typing_env()); trace!(?ty); - self.layout_of(ty).llvm_type(self) + self.type_array(self.type_i8(), self.layout_of(ty).size.bytes()) }; self.get_static_inner(def_id, llty) } diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 094b683ded56b..19b2f68107e6c 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -73,7 +73,7 @@ pub(crate) struct RustOffloadComponentMissing { #[derive(Diagnostic)] #[diag( - "using the offload feature requires -Z offload=.bc>" + "using the offload feature requires -Z offload=.ptx or .elf>" )] pub(crate) struct OffloadWithoutEnable; @@ -82,18 +82,20 @@ pub(crate) struct OffloadWithoutEnable; pub(crate) struct OffloadWithoutFatLTO; #[derive(Diagnostic)] -#[diag("using the `-Z offload=Host=/absolute/path/to/.bc` flag requires an absolute path")] +#[diag( + "using the `-Z offload=Host=/absolute/path/to/.ptx` or `.elf` flag requires an absolute path" +)] pub(crate) struct OffloadWithoutAbsPath; #[derive(Diagnostic)] #[diag( - "using the `-Z offload=Host=/absolute/path/to/.bc` flag must point to a .bc file produced by the device compilation (--emit=llvm-bc)" + "using the `-Z offload=Host=/absolute/path/to/.ptx` or `.elf` flag must point to a .ptx or .elf file produced by the device compilation" )] pub(crate) struct OffloadWrongFileName; #[derive(Diagnostic)] #[diag( - "the given path/file to `.bc` does not exist. Did you forget to run the device compilation first?" + "the given path/file to `.ptx` or `.elf` does not exist. Did you forget to run the device compilation first?" )] pub(crate) struct OffloadNonexistingPath; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 0cd26ca835971..f9863da230dfb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -262,6 +262,12 @@ pub(crate) fn add_global<'ll>(llmod: Module<'ll>, ty: &'ll Type, name_cstr: &CSt } pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { + unsafe { + assert_eq!( + crate::llvm::LLVMGlobalGetValueType(llglobal), + crate::llvm::LLVMTypeOf(constant_val) + ); + } unsafe { LLVMSetInitializer(llglobal, constant_val); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs index 60e0836a35d88..4f2369aef0d53 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs @@ -6,9 +6,8 @@ use super::ffi::{Module, Value}; type LLVMRustOffloadMapperFn = unsafe extern "C" fn(&Value, &Value, *const &Value); type LLVMRustOffloadWrapImagesFn = - for<'ll> unsafe extern "C" fn(Module<'ll>, *const c_char, *const c_char) -> bool; + for<'ll> unsafe extern "C" fn(Module<'ll>, *const c_char) -> bool; -use rustc_fs_util::path_to_c_string; use rustc_session::config::host_tuple; use rustc_session::filesearch; @@ -17,7 +16,6 @@ use crate::llvm; pub(crate) struct RustOffloadWrapper { LLVMRustOffloadMapper: LLVMRustOffloadMapperFn, LLVMRustOffloadWrapImages: LLVMRustOffloadWrapImagesFn, - lld_path: Option, // Keep the dynamic library loaded while the function pointers are used. _lib: libloading::Library, } @@ -59,18 +57,15 @@ impl RustOffloadWrapper { pub(crate) unsafe fn llvm_rust_offload_wrap_images<'ll>( &self, host_m: Module<'ll>, - device_bitcode_path: &CStr, + device_image_path: &CStr, ) -> bool { - let lld_c = self.lld_path.as_deref().map(path_to_c_string).unwrap_or_default(); - unsafe { - (self.LLVMRustOffloadWrapImages)(host_m, lld_c.as_ptr(), device_bitcode_path.as_ptr()) - } + unsafe { (self.LLVMRustOffloadWrapImages)(host_m, device_image_path.as_ptr()) } } fn call_dynamic( sysroot: &rustc_session::config::Sysroot, ) -> Result { - let (rust_offload_path, lld_path) = Self::get_offload_and_lld_paths(sysroot)?; + let rust_offload_path = Self::get_offload_path(sysroot)?; let lib = unsafe { libloading::Library::new(rust_offload_path)? }; let llvm_rust_offload_wrapper = @@ -81,14 +76,13 @@ impl RustOffloadWrapper { Ok(Self { LLVMRustOffloadMapper: llvm_rust_offload_wrapper, LLVMRustOffloadWrapImages: llvm_rust_offload_wrap_images, - lld_path, _lib: lib, }) } - fn get_offload_and_lld_paths( + fn get_offload_path( sysroot: &rustc_session::config::Sysroot, - ) -> Result<(PathBuf, Option), RustOffloadLibraryError> { + ) -> Result { let llvm_version_major = llvm::LLVMRustVersionMajor(); let mut searched = Vec::new(); @@ -102,11 +96,7 @@ impl RustOffloadWrapper { continue; } - let lld_path = filesearch::make_target_bin_path(root, host_tuple()) - .join(format!("rust-lld{}", std::env::consts::EXE_SUFFIX)); - let lld_path = lld_path.is_file().then_some(lld_path); - - return Ok((rust_offload_path, lld_path)); + return Ok(rust_offload_path); } Err(RustOffloadLibraryError::NotFound { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 2d64c63cf9ae4..82bd5584211c0 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -20,7 +20,6 @@ use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; use crate::diagnostics::SymbolAlreadyDefined; -use crate::type_of::LayoutLlvmExt; use crate::{base, llvm}; impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { @@ -37,7 +36,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { // out the llvm type from the actual evaluated initializer. let ty = if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) }; - let llty = self.layout_of(ty).llvm_type(self); + let llty = self.type_array(self.type_i8(), self.layout_of(ty).size.bytes()); let g = self.define_global(symbol_name, llty).unwrap_or_else(|| { self.sess() diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index c3bace9569dd0..10baf16915d15 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -72,8 +72,13 @@ fn process_builtin_attrs( AttributeKind::Cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name), AttributeKind::Inline(inline, span) => { - codegen_fn_attrs.inline = *inline; - interesting_spans.inline = Some(*span); + // On an `async fn` (or similar), inlining hints are meant for the code the user + // wrote, which lives in the body coroutine. The constructor is trivial and left to + // the usual heuristics. + if !constructs_desugared_body_coroutine(tcx, did) { + codegen_fn_attrs.inline = *inline; + interesting_spans.inline = Some(*span); + } } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::RustcAlign { align, .. } => codegen_fn_attrs.alignment = Some(*align), @@ -297,9 +302,54 @@ fn process_builtin_attrs( } } + // The body coroutine can't carry attributes of its own, so it takes the ones describing the + // code the user wrote from the `async fn` (or similar) it was desugared from. This makes e.g. + // `#[inline(never)] async fn` affect `Future::poll`. See #129347. + if is_desugared_body_coroutine(tcx, did) { + let parent = tcx.local_parent(did); + // `#[rustc_force_inline]` is already rejected on the parent. Propagating it would only + // cause `CheckForceInline` to report the same attribute again for the coroutine. + if let Some((inline, span)) = find_attr!( + tcx, + parent, + Inline(inline, span) if !matches!(inline, InlineAttr::Force { .. }) => (*inline, *span) + ) { + codegen_fn_attrs.inline = inline; + interesting_spans.inline = Some(span); + } + // Unlike inlining hints, `#[cold]` stays on the constructor as well: calling it is just as + // unlikely, and its call sites are only recognized as cold through that. + if find_attr!(tcx, parent, Cold) { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; + } + } + interesting_spans } +/// Whether `did` is the coroutine holding the body of an `async fn`, `gen fn`, `async gen fn`, or +/// `async` closure, as opposed to one written as an `async {}` block. +fn is_desugared_body_coroutine(tcx: TyCtxt<'_>, did: LocalDefId) -> bool { + matches!( + tcx.coroutine_kind(did), + Some(hir::CoroutineKind::Desugared( + _, + hir::CoroutineSource::Fn | hir::CoroutineSource::Closure + )) + ) +} + +/// Whether `did` is an `async fn`, `gen fn`, `async gen fn`, or `async` closure, i.e. its body +/// does nothing but construct a [desugared body coroutine](is_desugared_body_coroutine). +fn constructs_desugared_body_coroutine(tcx: TyCtxt<'_>, did: LocalDefId) -> bool { + tcx.hir_maybe_body_owned_by(did).is_some_and(|body| { + matches!( + body.value.kind, + hir::ExprKind::Closure(closure) if is_desugared_body_coroutine(tcx, closure.def_id) + ) + }) +} + /// Applies overrides for codegen fn attrs. These often have a specific reason why they're necessary. /// Please comment why when adding a new one! fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut CodegenFnAttrs) { @@ -336,7 +386,17 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // its parent function, which effectively inherits the features anyway. Boxing this closure // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. - if tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { + // + // That reasoning doesn't hold for the body coroutine of an `async fn` or `gen fn`: it is never + // inlined into the function constructing it, yet its body was checked as part of that function. + // It always inherits, so it is compiled with the same features as the function itself. + if tcx.is_closure_like(did.to_def_id()) + && (codegen_fn_attrs.inline != InlineAttr::Always + || matches!( + tcx.coroutine_kind(did), + Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Fn)) + )) + { let owner_id = tcx.parent(did.to_def_id()); if tcx.def_kind(owner_id).has_codegen_attrs() { codegen_fn_attrs diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 941af4a4ab01d..95ca582e011df 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_targ use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{Symbol, bug, span_bug, sym}; +use rustc_span::{Symbol, bug, kw, span_bug, sym}; use tracing::trace; use super::memory::MemoryKind; @@ -231,7 +231,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let val = layout.align.bytes(); self.write_scalar(Scalar::from_target_usize(val, self), dest)?; } - sym::offset_of => { + kw::OffsetOf => { let tp_ty = instance.args.type_at(0); let variant = self.read_scalar(&args[0])?.to_u32()?; diff --git a/compiler/rustc_error_codes/src/error_codes/E0452.md b/compiler/rustc_error_codes/src/error_codes/E0452.md index 429813a7cdd4e..581687e86974a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0452.md +++ b/compiler/rustc_error_codes/src/error_codes/E0452.md @@ -3,7 +3,7 @@ An invalid lint attribute has been given. Erroneous code example: ```compile_fail,E0452 -#![allow(foo = "")] // error: malformed lint attribute +#![allow(reason = "", foo)] // error: malformed lint attribute ``` Lint attributes only accept a list of identifiers (where each identifier is a diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3472180ae26dc..66687cfcbb06e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -301,8 +301,6 @@ declare_features! ( /// Allows features specific to auto traits. /// Renamed from `optin_builtin_traits`. (unstable, auto_traits, "1.50.0", Some(13231)), - /// Allows builtin # foo() syntax - (internal, builtin_syntax, "1.71.0", Some(110680)), /// Allows `#[doc(notable_trait)]`. /// Renamed from `doc_spotlight`. (unstable, doc_notable_trait, "1.52.0", Some(45040)), @@ -310,6 +308,8 @@ declare_features! ( (unstable, dropck_eyepatch, "1.10.0", Some(34761)), /// Allows using the `#[fundamental]` attribute. (unstable, fundamental, "1.0.0", Some(29635)), + /// Allows internal syntax. + (internal, internal_syntax, "CURRENT_RUSTC_VERSION", Some(110680)), /// Allows using `#[link_name="llvm.*"]`. (internal, link_llvm_intrinsics, "1.0.0", Some(29602)), /// Allows using the `#[linkage = ".."]` attribute. diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 85b666372074a..8b55734d90c8f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, kw, sym}; use crate::check::check_function_signature; use crate::diagnostics::{UnrecognizedIntrinsicFunction, WrongNumberOfGenericArgumentsToIntrinsic}; @@ -66,6 +66,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi // safe extern fns are otherwise unprecedented. // tidy-alphabetical-start + | kw::OffsetOf | sym::abort_immediate | sym::add_with_overflow | sym::aggregate_raw_ptr @@ -141,7 +142,6 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::needs_drop | sym::offload | sym::offload_get_num_devices - | sym::offset_of | sym::overflow_checks | sym::powf | sym::powi @@ -271,7 +271,7 @@ pub(crate) fn check_intrinsic_type( (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::type_id_size_of => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, tcx.types.usize)), - sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize), + kw::OffsetOf => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize), sym::field_offset => (1, 0, vec![], tcx.types.usize), sym::rustc_peek => (1, 0, vec![param(0)], param(0)), sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index bf0d64d78d395..02acd8dc58918 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -402,7 +402,9 @@ fn bounds_from_generic_clauses<'tcx>( ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); - if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) { + if !tcx.is_implicit_trait(def_id, ty::IncludeSizedImplicitBounds::No) + && !tcx.is_lang_item(def_id, LangItem::Sized) + { // Do not add that restriction to the list if it is a positive requirement. entry.push(trait_predicate.def_id()); } diff --git a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs index ae384a67ee6aa..ba1c1197bee92 100644 --- a/compiler/rustc_hir_analysis/src/collect/clauses_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/clauses_of.rs @@ -7,7 +7,8 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{ - self, GenericClauses, ImplTraitInTraitData, Ty, TyCtxt, TypeVisitable, TypeVisitor, Upcast, + self, GenericClauses, ImplTraitInTraitData, IncludeSizedImplicitBounds, Ty, TyCtxt, + TypeVisitable, TypeVisitor, Upcast, }; use rustc_span::{DUMMY_SP, Ident, Span, bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -195,19 +196,13 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - tcx.types.self_param, - self_bounds, - ImpliedBoundsContext::TraitDef(def_id), - span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, tcx.types.self_param, self_bounds, ImpliedBoundsContext::TraitDef(def_id), span, + IncludeSizedImplicitBounds::Yes, ); clauses.extend(bounds); } @@ -234,19 +229,13 @@ fn gather_explicit_clauses_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generi let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Vec::new(); // Implicit bounds are added to type params unless a `?Trait` bound is found - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - param_ty, - &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), - param.span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, param_ty, &[], ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, + IncludeSizedImplicitBounds::Yes, ); trace!(?bounds); clauses.extend(bounds); @@ -690,19 +679,13 @@ pub(super) fn implied_clauses_with_filter<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - self_param_ty, - superbounds, - ImpliedBoundsContext::TraitDef(trait_def_id), - item.span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, self_param_ty, superbounds, ImpliedBoundsContext::TraitDef(trait_def_id), item.span, + IncludeSizedImplicitBounds::Yes, ); } //`ConstIfConst` is only interested in `[const]` bounds. @@ -992,19 +975,13 @@ impl<'tcx> ItemCtxt<'tcx> { match param.kind { hir::GenericParamKind::Type { .. } => { let param_ty = self.lowerer().lower_ty_param(param.hir_id); - self.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - param_ty, - &[], - ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), - param.span, - ); - self.lowerer().add_default_traits( + self.lowerer().add_implicit_bounds( &mut bounds, param_ty, &[], ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, + IncludeSizedImplicitBounds::Yes, ); } hir::GenericParamKind::Lifetime { .. } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 5ed5745310f16..131af48cd52bd 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::{ - self, GenericArgs, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, Upcast, shift_vars, + self, GenericArgs, IncludeSizedImplicitBounds, PredicateProxy, Ty, TyCtxt, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, shift_vars, }; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{Span, bug, span_bug}; @@ -54,19 +54,13 @@ fn associated_type_bounds<'tcx>( | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { // Implicit bounds are added to associated types unless a `?Trait` bound is found. - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - item_ty, - hir_bounds, - ImpliedBoundsContext::AssociatedTypeOrImplTrait, - span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, item_ty, hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, + IncludeSizedImplicitBounds::Yes, ); // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. @@ -381,19 +375,13 @@ fn opaque_type_bounds<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_implicit_sizedness_bounds( - &mut bounds, - item_ty, - hir_bounds, - ImpliedBoundsContext::AssociatedTypeOrImplTrait, - span, - ); - icx.lowerer().add_default_traits( + icx.lowerer().add_implicit_bounds( &mut bounds, item_ty, hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, + IncludeSizedImplicitBounds::Yes, ); } //`ConstIfConst` is only interested in `[const]` bounds. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 0b7df89551da8..88924a9d6a98e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -10,8 +10,8 @@ use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ - self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, Upcast, + self as ty, IncludeSizedImplicitBounds, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, }; use rustc_span::{ErrorGuaranteed, Ident, Span, bug, kw}; use rustc_trait_selection::traits; @@ -138,6 +138,29 @@ fn add_trait_bound<'tcx>( } impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// Adds implicit sizedness, and in the future `Move` and `Forget`, and default trait bounds. + pub(crate) fn add_implicit_bounds( + &self, + bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, + self_ty: Ty<'tcx>, + hir_bounds: &[hir::GenericBound<'_>], + context: ImpliedBoundsContext<'tcx>, + span: Span, + // Sized is treated slightly more specially than the other implicit bounds. + include_sized: IncludeSizedImplicitBounds, + ) { + // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` + if find_attr!(self.tcx(), crate, RustcNoImplicitBounds) { + return; + } + + self.add_default_traits(bounds, self_ty, hir_bounds, context, span); + + if let IncludeSizedImplicitBounds::Yes = include_sized { + self.add_implicit_sizedness_bounds(bounds, self_ty, hir_bounds, context, span); + } + } + /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type. /// /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit @@ -146,7 +169,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// bounds are present. /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if /// a `?Sized` bound is present. - pub(crate) fn add_implicit_sizedness_bounds( + fn add_implicit_sizedness_bounds( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, @@ -156,11 +179,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) { let tcx = self.tcx(); - // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` - if find_attr!(tcx, crate, RustcNoImplicitBounds) { - return; - } - let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span); @@ -208,7 +226,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - pub(crate) fn add_default_traits( + fn add_default_traits( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, @@ -224,7 +242,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `experimental_default_bounds` bound to the `bounds` if appropriate. /// /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`. - pub(crate) fn add_default_trait( + fn add_default_trait( &self, trait_: LangItem, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, @@ -244,23 +262,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if let Some(trait_did) = tcx.lang_items().get(trait_) - && self.should_add_default_traits(trait_did, hir_bounds, context) + && !collect_bounds(hir_bounds, context, trait_did).any() { add_trait_bound(tcx, bounds, self_ty, trait_did, span); } } - /// Returns `true` if default trait bound should be added. - fn should_add_default_traits( - &self, - trait_def_id: DefId, - hir_bounds: &[hir::GenericBound<'_>], - context: ImpliedBoundsContext<'tcx>, - ) -> bool { - let collected = collect_bounds(hir_bounds, context, trait_def_id); - !find_attr!(self.tcx(), crate, RustcNoImplicitBounds) && !collected.any() - } - pub(crate) fn require_bound_to_relax_default_trait( &self, trait_ref: hir::TraitRef<'_>, @@ -269,7 +276,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res - && (tcx.is_lang_item(def_id, LangItem::Sized) || tcx.is_default_trait(def_id)) + && (tcx.is_lang_item(def_id, LangItem::Sized) + || tcx.is_implicit_trait(def_id, IncludeSizedImplicitBounds::No)) { return; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index c652174f9ba68..4a763e5b89316 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -9,8 +9,8 @@ use rustc_hir::{self as hir, HirId}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ - self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, - TypeVisitableExt, Upcast, + self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, IncludeSizedImplicitBounds, Ty, + TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{ErrorGuaranteed, Span}; @@ -75,7 +75,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - self.add_default_traits( + self.add_implicit_bounds( &mut user_written_bounds, dummy_self, &hir_bounds @@ -84,6 +84,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect::>(), ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, + IncludeSizedImplicitBounds::No, ); let (mut elaborated_trait_bounds, elaborated_projection_bounds) = diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5edf50d5cb33b..f15b8c81c51d2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -15,7 +15,7 @@ //! [^1]: This includes types, lifetimes / regions, constants in type positions, //! trait references and bounds. -mod bounds; +pub(crate) mod bounds; mod cmse; mod dyn_trait; pub mod errors; @@ -43,9 +43,9 @@ use rustc_lint_defs::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::{ - self, Const, FnSigKind, GenericArgKind, GenericParamDefKind, LitToConstInput, Ty, TyCtxt, - TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, Upcast, const_lit_matches_ty, - fold_regions, + self, Const, FnSigKind, GenericArgKind, GenericParamDefKind, IncludeSizedImplicitBounds, + LitToConstInput, Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, + Upcast, const_lit_matches_ty, fold_regions, }; use rustc_session::diagnostics::feature_err; use rustc_span::def_id::{LocalModId, ModId}; @@ -3326,12 +3326,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - self.add_implicit_sizedness_bounds( + self.add_implicit_bounds( &mut bounds, self_ty, hir_bounds, ImpliedBoundsContext::AssociatedTypeOrImplTrait, hir_ty.span, + IncludeSizedImplicitBounds::Yes, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); self_ty diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index f3cba3a27d69f..7ccd7eb435d03 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::adjustment::{ OverloadedDeref, PointerCoercion, }; use rustc_middle::ty::{self, Ty}; -use rustc_span::{Span, span_bug, sym}; +use rustc_span::{Span, kw, span_bug, sym}; use tracing::debug; use crate::method::{MethodCallee, TreatNotYetDefinedOpaques}; @@ -203,7 +203,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); let (Some(imm_tr), imm_op) = (match op { - PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref), + PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), kw::Deref), PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index), }) else { // Bail if `Deref` or `Index` isn't defined. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7df2ede5053b2..6dc3f74f054f1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -36,7 +36,7 @@ use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::{Resolver, ResolverOutputs}; -use rustc_session::config::{Input, OutFileName, OutputFilenames, OutputType}; +use rustc_session::config::{Input, Offload, OutFileName, OutputFilenames, OutputType}; use rustc_session::diagnostics::feature_err; use rustc_session::output::{filename_for_input, invalid_output_for_target}; use rustc_session::search_paths::PathKind; @@ -1485,6 +1485,16 @@ pub fn collect_crate_types( } } + // GPU code is never run as a binary; the offload runtime looks up kernels by + // name, and only cdylibs export their symbols. + if session.opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Device(_))) { + for crate_type in &mut base { + if *crate_type == CrateType::Executable { + *crate_type = CrateType::Cdylib; + } + } + } + base.retain(|crate_type| { if invalid_output_for_target(session, *crate_type) { session.dcx().emit_warn(diagnostics::UnsupportedCrateTypeForTarget { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 75552ab759fd5..12b52f4e2801e 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -1,7 +1,7 @@ use rustc_attr_ir::lang_items::LangItem; use rustc_hir as hir; use rustc_lint_defs::{declare_lint, declare_lint_pass}; -use rustc_middle::ty::Unnormalized; +use rustc_middle::ty::{IncludeSizedImplicitBounds, Unnormalized}; use crate::{LateContext, LateLintPass, LintContext}; @@ -51,7 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .map(Unnormalized::skip_norm_wip) .filter_map(|(clause, _)| clause.as_trait_clause()) .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), LangItem::MetaSized)) - .filter(|pred| !cx.tcx.is_default_trait(pred.def_id())); + .filter(|pred| { + !cx.tcx.is_implicit_trait(pred.def_id(), IncludeSizedImplicitBounds::No) + }); if direct_super_traits_iter.count() > 1 { cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp index 5c0fabb3fcee8..6a51e58f896be 100644 --- a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp @@ -1,29 +1,22 @@ #include "../SuppressLLVMWarnings.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Frontend/Offloading/OffloadWrapper.h" #include "llvm/Frontend/Offloading/Utility.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" -#include "llvm/MC/TargetRegistry.h" -#include "llvm/Support/CodeGen.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ValueMapper.h" @@ -34,18 +27,6 @@ using namespace llvm; -static Error writeFile(StringRef Filename, StringRef Data) { - Expected> OutputOrErr = - FileOutputBuffer::create(Filename, Data.size()); - if (!OutputOrErr) - return OutputOrErr.takeError(); - std::unique_ptr Output = std::move(*OutputOrErr); - llvm::copy(Data, Output->getBufferStart()); - if (Error E = Output->commit()) - return E; - return Error::success(); -} - // Clone OldFn into NewFn, remapping its arguments to RebuiltArgs. // Each arg of OldFn is replaced with the corresponding value in RebuiltArgs. // For scalars, RebuiltArgs contains the value cast and/or truncated to the @@ -96,37 +77,44 @@ static bool reportAndFailWrappingImages(Error E, const char *What) { return false; } +/// Returns the target architecture (e.g. "sm_86") named by the `.target` +/// directive of the given PTX text. The result points into `PtxBuf`. +static Expected getPtxArch(MemoryBufferRef PtxBuf) { + const Regex TargetRe("^\\.target[[:space:]]+([^,[:space:]]+)", + Regex::Newline); + + SmallVector M; + if (!TargetRe.match(PtxBuf.getBuffer(), &M)) + return createStringError("no .target directive in %s", + PtxBuf.getBufferIdentifier().str().c_str()); + + return M[1]; +} + static Expected> -assembleWithPtxas(StringRef Ptx, StringRef Arch) { +assembleWithPtxas(MemoryBufferRef PtxBuf) { + Expected ArchOrErr = getPtxArch(PtxBuf); + if (!ArchOrErr) + return ArchOrErr.takeError(); + const ErrorOr Ptxas = sys::findProgramByName("ptxas"); if (!Ptxas) return createStringError(Ptxas.getError(), "ptxas not found in PATH"); - SmallString<128> PtxFilePath; - if (std::error_code E = - sys::fs::createTemporaryFile("rust-offload", "ptx", PtxFilePath)) - return errorCodeToError(E); - SmallString<128> CubinFilePath; if (std::error_code E = sys::fs::createTemporaryFile("rust-offload", "cubin", CubinFilePath)) return errorCodeToError(E); auto Cleanup = scope_exit([&] { - if (std::error_code E = sys::fs::remove(PtxFilePath)) - (void)reportAndFailWrappingImages( - errorCodeToError(E), "assembleWithPtxas: PtxFilePath cleanup"); if (std::error_code E = sys::fs::remove(CubinFilePath)) (void)reportAndFailWrappingImages( errorCodeToError(E), "assembleWithPtxas: CubinFilePath cleanup"); }); - if (Error E = writeFile(PtxFilePath, Ptx)) - return std::move(E); - const StringRef Args[] = { - *Ptxas, "-m64", "-O3", "--gpu-name", - Arch, "--output-file", CubinFilePath, PtxFilePath, + *Ptxas, "-m64", "-O3", "--gpu-name", + *ArchOrErr, "--output-file", CubinFilePath, PtxBuf.getBufferIdentifier(), }; std::string ErrorMsg; @@ -145,130 +133,37 @@ assembleWithPtxas(StringRef Ptx, StringRef Arch) { return std::move(*CubinOrError); } -static Expected> -linkWithRustLld(StringRef Obj, StringRef LldPath) { - SmallString<128> ObjFilePath; - if (std::error_code E = - sys::fs::createTemporaryFile("rust-offload", "o", ObjFilePath)) - return errorCodeToError(E); - - SmallString<128> SoFilePath; - if (std::error_code E = - sys::fs::createTemporaryFile("rust-offload", "so", SoFilePath)) - return errorCodeToError(E); - - auto Cleanup = scope_exit([&] { - if (std::error_code E = sys::fs::remove(ObjFilePath)) - (void)reportAndFailWrappingImages(errorCodeToError(E), - "linkWithRustLld: ObjFilePath cleanup"); - if (std::error_code E = sys::fs::remove(SoFilePath)) - (void)reportAndFailWrappingImages(errorCodeToError(E), - "linkWithRustLld: SoFilePath cleanup"); - }); - - if (Error E = writeFile(ObjFilePath, Obj)) - return std::move(E); - - const StringRef Args[] = { - LldPath, "-flavor", "gnu", "-shared", - "--no-undefined", "-o", SoFilePath, ObjFilePath, - }; - - std::string ErrorMsg; - const int Status = - sys::ExecuteAndWait(LldPath, Args, std::nullopt, {}, 0, 0, &ErrorMsg); - - if (Status != 0) - return createStringError("linkWithRustLld: status %d: %s", Status, - ErrorMsg.c_str()); - - ErrorOr> ElfOrError = - MemoryBuffer::getFileAsStream(SoFilePath); - if (!ElfOrError) - return errorCodeToError(ElfOrError.getError()); - - return std::move(*ElfOrError); -} - -static Expected> -compileDeviceImage(MemoryBufferRef Input, const char *LldPath) { - LLVMContext Ctx; - Expected> ModOrErr = parseBitcodeFile(Input, Ctx); - if (!ModOrErr) - return ModOrErr.takeError(); - Module &M = **ModOrErr; - - const Triple &DeviceTriple = M.getTargetTriple(); - StringRef Arch; - for (Function &F : M) - if (F.hasFnAttribute("target-cpu")) { - Arch = F.getFnAttribute("target-cpu").getValueAsString(); - break; - } - - if (Arch.empty()) - return createStringError("no target-cpu attribute in device bitcode"); - - std::string ErrorMsg; - const Target *DeviceTarget = - TargetRegistry::lookupTarget(DeviceTriple, ErrorMsg); - if (!DeviceTarget) - return createStringError(ErrorMsg); - - std::unique_ptr TM(DeviceTarget->createTargetMachine( - DeviceTriple, Arch, /*Features=*/"", TargetOptions(), Reloc::PIC_)); - if (!TM) - return createStringError("createTargetMachine failed for %s", - DeviceTriple.str().c_str()); - - const bool IsNvptx = DeviceTriple.isNVPTX(); - - legacy::PassManager PM; - SmallString<0> Emitted; - raw_svector_ostream OS(Emitted); - const CodeGenFileType FileType = - IsNvptx ? CodeGenFileType::AssemblyFile : CodeGenFileType::ObjectFile; - if (TM->addPassesToEmitFile(PM, OS, nullptr, FileType)) - return createStringError("target %s cannot emit %s", - DeviceTriple.str().c_str(), - IsNvptx ? "assembly" : "object"); - - PM.run(**ModOrErr); - - if (IsNvptx) - return assembleWithPtxas(Emitted, Arch); - if (DeviceTriple.isAMDGPU()) { - if (!LldPath || !*LldPath) - return createStringError("rust-lld path was not provided for %s", - DeviceTriple.str().c_str()); - return linkWithRustLld(Emitted, LldPath); - } - - return createStringError("unsupported offload target %s", - DeviceTriple.str().c_str()); -} - extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, - const char *LldPath, - const char *DeviceBitcodePath) { + const char *DeviceImagePath) { Module &M = *unwrap(HostMRef); if (!hasOffloadEntries(M)) return true; ErrorOr> BufOrErr = - MemoryBuffer::getFile(DeviceBitcodePath); + MemoryBuffer::getFile(DeviceImagePath); if (std::error_code EC = BufOrErr.getError()) - return reportAndFailWrappingImages(createFileError(DeviceBitcodePath, EC), - "device bitcode"); + return reportAndFailWrappingImages(createFileError(DeviceImagePath, EC), + "device image"); std::unique_ptr Buf = std::move(*BufOrErr); - Expected> ImageOrErr = - compileDeviceImage(Buf->getMemBufferRef(), LldPath); - if (!ImageOrErr) - return reportAndFailWrappingImages(ImageOrErr.takeError(), - "device compile"); + std::unique_ptr DeviceImage; + StringRef Ext = sys::path::extension(DeviceImagePath); + if (Ext == ".ptx") { + Expected> CubinOrErr = + assembleWithPtxas(Buf->getMemBufferRef()); + if (!CubinOrErr) + return reportAndFailWrappingImages(CubinOrErr.takeError(), "ptxas"); + DeviceImage = std::move(*CubinOrErr); + } else if (Ext == ".elf") { + DeviceImage = std::move(Buf); + } else { + return reportAndFailWrappingImages( + createStringError("unsupported device image %s: expected .ptx or .elf", + DeviceImagePath), + "device image path"); + } - StringRef ImageBuf = (*ImageOrErr)->getBuffer(); + StringRef ImageBuf = DeviceImage->getBuffer(); ArrayRef Image(ImageBuf.data(), ImageBuf.size()); if (Error E = offloading::wrapOpenMPBinaries( diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3b96713305337..976512fba3f53 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -48,7 +48,8 @@ use rustc_structures::{CrateType, Limit}; use rustc_type_ir::TyKind::*; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{ - CollectAndApply, PlaceholderType, WithCachedTypeInfo, elaborate, search_graph, + CollectAndApply, IncludeSizedImplicitBounds, PlaceholderType, WithCachedTypeInfo, elaborate, + search_graph, }; use tracing::{debug, instrument}; @@ -955,6 +956,18 @@ impl<'tcx> TyCtxt<'tcx> { self.default_traits().iter().any(|&default_trait| self.is_lang_item(def_id, default_trait)) } + /// Returns true if a trait is an "implicit trait", which is a trait which is added + /// to bounds on generic types automatically by the compiler. + pub fn is_implicit_trait( + self, + def_id: DefId, + including_sized: IncludeSizedImplicitBounds, + ) -> bool { + self.is_default_trait(def_id) + // NOTE: add move and forget here later + || (matches!(including_sized, IncludeSizedImplicitBounds::Yes) && self.is_sizedness_trait(def_id)) + } + pub fn is_sizedness_trait(self, def_id: DefId) -> bool { matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized)) } diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index eb81ea291759b..c62bdcebec389 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -12,8 +12,8 @@ use rustc_span::{DUMMY_SP, Span, Symbol, bug}; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::CanonicalInputData; use rustc_type_ir::{ - BoundVar, CollectAndApply, DebruijnIndex, Interner, RegionVid, TypeFoldable, Unnormalized, - VisitorResult, WithCachedTypeInfo, search_graph, try_visit, + BoundVar, CollectAndApply, DebruijnIndex, IncludeSizedImplicitBounds, Interner, RegionVid, + TypeFoldable, Unnormalized, VisitorResult, WithCachedTypeInfo, search_graph, try_visit, }; use crate::dep_graph::{DepKind, DepNodeIndex}; @@ -527,6 +527,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_default_trait(def_id) } + fn is_implicit_trait( + self, + def_id: Self::TraitId, + including_sized: IncludeSizedImplicitBounds, + ) -> bool { + self.is_implicit_trait(def_id, including_sized) + } + fn is_sizedness_trait(self, def_id: DefId) -> bool { self.is_sizedness_trait(def_id) } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3d560a9f18815..398633cb3311c 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -141,7 +141,7 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable>, { - self.instantiate_bound_regions(value, |_| self.lifetimes.re_erased).0 + self.instantiate_bound_regions_uncached(value, |_| self.lifetimes.re_erased) } /// Anonymize all bound variables in `value`, this is mostly used to improve caching. diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index d116806fc0b73..a8ae60b4daba7 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -14,7 +14,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, bug, sym}; +use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, bug, kw, sym}; use tracing::{debug, instrument}; use crate::builder::Builder; @@ -343,7 +343,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, ) { let (trait_item, method) = match mutability { - Mutability::Not => (LangItem::Deref, sym::deref), + Mutability::Not => (LangItem::Deref, kw::Deref), Mutability::Mut => (LangItem::DerefMut, sym::deref_mut), }; let borrow_kind = super::util::ref_pat_borrow_kind(mutability); diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 569fbd41e1b22..6b159074493f9 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -26,13 +26,15 @@ const NEEDS_CANONICAL: TypeFlags = TypeFlags::from_bits( .unwrap(); #[derive(Debug, Clone, Copy)] -enum CanonicalizeInputKind { +enum CanonicalizeInputKind { /// When canonicalizing the `param_env`, we keep `'static` as merging /// trait candidates relies on it when deciding whether a where-bound /// is trivial. ParamEnv, /// When canonicalizing predicates, we don't keep `'static`. - Predicate, + /// `param_env_var_kinds` caches the interned variable kinds to be + /// reused if there are no new vars. + Predicate { param_env_var_kinds: Option }, } /// Whether we're canonicalizing a query input or the query response. @@ -41,8 +43,8 @@ enum CanonicalizeInputKind { /// while canonicalizing the response happens in the context of the /// query. #[derive(Debug, Clone, Copy)] -enum CanonicalizeMode { - Input(CanonicalizeInputKind), +enum CanonicalizeMode { + Input(CanonicalizeInputKind), /// FIXME: We currently return region constraints referring to /// placeholders and inference variables from a binder instantiated /// inside of the query. @@ -68,14 +70,14 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner delegate: &'a D, // Immutable field. - canonicalize_mode: CanonicalizeMode, + canonicalize_mode: CanonicalizeMode, // Mutable fields. state: Box>, } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { - fn new(delegate: &'a D, canonicalize_mode: CanonicalizeMode) -> Self { + fn new(delegate: &'a D, canonicalize_mode: CanonicalizeMode) -> Self { Canonicalizer { delegate, canonicalize_mode, state: delegate.obtain_canonicalizer_state() } } @@ -105,15 +107,18 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { if !param_env.has_type_flags(NEEDS_CANONICAL) { let rest_canonicalizer = Canonicalizer::new( delegate, - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate), + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds: None, + }), ); return (param_env, rest_canonicalizer); } // Do the `env` canonicalization, and then convert the canonicalizer to `rest` form for - // subsequent use. - let do_env_and_make_rest = || { + // subsequent use, also returning the optionally interned (i.e., uniquely identified) + // canonicalized variable kind list in case cache is used, so it can also be cached. + let do_env_and_make_rest = |intern_var_kinds: bool| { let mut env_canonicalizer = Canonicalizer::new( delegate, CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), @@ -133,12 +138,17 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // // We clear the cache rather than deleting it or replacing it with an empty cache. This // lets the allocated capacity be reused later. - let mut rest_canonicalizer = env_canonicalizer; - rest_canonicalizer.canonicalize_mode = - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate); + let param_env_var_kinds = intern_var_kinds + .then(|| delegate.cx().mk_canonical_var_kinds(&env_canonicalizer.state.var_kinds)); + let mut rest_canonicalizer = Canonicalizer { + canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds, + }), + ..env_canonicalizer + }; rest_canonicalizer.state.cache.clear(); - (param_env, rest_canonicalizer) + (param_env, rest_canonicalizer, param_env_var_kinds) }; // Check whether we can use the global cache for this param_env. As we only use @@ -153,11 +163,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Entry::Vacant(e) => { // Cache miss. Do `env` canonicalization and get `rest_canonicalizer`, and // fill in the cache entry. - let (param_env, rest_canonicalizer) = do_env_and_make_rest(); + let (param_env, rest_canonicalizer, var_kinds) = do_env_and_make_rest(true); e.insert(CanonicalParamEnvCacheEntry { param_env, variables: rest_canonicalizer.state.variables.clone(), - var_kinds: rest_canonicalizer.state.var_kinds.clone(), + var_kinds: var_kinds.unwrap(), // SAFETY: The iterated elements go straight back into a hashmap. #[allow(rustc::potential_query_instability)] variable_lookup_table: rest_canonicalizer @@ -174,10 +184,12 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let e = e.get(); let mut rest_canonicalizer = Canonicalizer::new( delegate, - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate), + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds: Some(e.var_kinds), + }), ); rest_canonicalizer.state.variables.clone_from(&e.variables); - rest_canonicalizer.state.var_kinds.clone_from(&e.var_kinds); + e.var_kinds.as_slice().clone_into(&mut rest_canonicalizer.state.var_kinds); rest_canonicalizer .state .variable_lookup_table @@ -187,7 +199,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }) } else { // Do `env` canonicalization and get `rest_canonicalizer`. - do_env_and_make_rest() + let (param_env, rest_canonicalizer, _) = do_env_and_make_rest(false); + (param_env, rest_canonicalizer) } } @@ -278,7 +291,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // during canonicalization in the new solver. let max_universe = match self.canonicalize_mode { // All placeholders and vars are canonicalized in the root universe. - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { debug_assert!( self.state .var_kinds @@ -309,7 +322,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { .unwrap_or(ty::UniverseIndex::ROOT) } }; - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&self.state.var_kinds); + let var_kinds = match self.canonicalize_mode { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { + param_env_var_kinds: Some(cached), + }) if cached.len() == self.state.variables.len() => { + debug_assert_eq!(cached.as_slice(), self.state.var_kinds.as_slice()); + cached + } + _ => self.delegate.cx().mk_canonical_var_kinds(&self.state.var_kinds), + }; // We have finished with this canonicalizer and can return its state to the delegate for // later reuse. @@ -330,7 +351,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let sub_root = self.get_or_insert_sub_root(vid); let ui = match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => ty::UniverseIndex::ROOT, + CanonicalizeMode::Input(_) => ty::UniverseIndex::ROOT, CanonicalizeMode::Response { .. } => self .delegate .universe_of_ty(vid) @@ -359,7 +380,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } }, ty::Placeholder(placeholder) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderTy(PlaceholderType::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -368,7 +389,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, ty::Param(_) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderTy(PlaceholderType::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -429,7 +450,7 @@ impl, I: Interner> TypeFolder for Canonicaliz // We don't canonicalize `ReStatic` in the `param_env` as we use it // when checking whether a `ParamEnv` candidate is global. ty::ReStatic => match self.canonicalize_mode { - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -541,7 +562,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ); match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::Const(ty::UniverseIndex::ROOT) } CanonicalizeMode::Response { .. } => { @@ -552,7 +573,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ty::InferConst::Fresh(_) => unimplemented!(), }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -563,7 +584,7 @@ impl, I: Interner> TypeFolder for Canonicaliz } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => { + CanonicalizeMode::Input(_) => { CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon( ty::UniverseIndex::ROOT, self.state.variables.len().into(), @@ -592,7 +613,7 @@ impl, I: Interner> TypeFolder for Canonicaliz match self.canonicalize_mode { CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { max_input_universe: _ } => {} - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { panic!("erasing 'static in env") } } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 5ae19b2eb6935..685897188a6bf 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -10,9 +10,9 @@ use rustc_type_ir::solve::{ QueryResultOrRerunNonErased, RerunNonErased, RerunReason, RerunResultExt, SizedTraitKind, }; use rustc_type_ir::{ - self as ty, ClausePolarity, ExistentialPredicate, FieldInfo, Interner, MayBeErased, Movability, - Region, TraitClause, TraitRef, TypeVisitableExt as _, TypingMode, Unnormalized, Upcast as _, - elaborate, + self as ty, ClausePolarity, ExistentialPredicate, FieldInfo, IncludeSizedImplicitBounds, + Interner, MayBeErased, Movability, Region, TraitClause, TraitRef, TypeVisitableExt as _, + TypingMode, Unnormalized, Upcast as _, elaborate, }; use tracing::{debug, instrument, trace, warn}; @@ -1413,7 +1413,13 @@ where // Backward compatibility for default auto traits. // Test: ui/traits/default_auto_traits/extern-types.rs - ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(), + ty::Foreign(..) + if self + .cx() + .is_implicit_trait(goal.predicate.def_id(), IncludeSizedImplicitBounds::No) => + { + check_impls() + } // These types cannot be structurally decomposed into constituent // types, and therefore have no built-in auto impl. diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index ab220cc56a9e0..72947b1c576c8 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -4079,21 +4079,6 @@ impl IntoDiagArg for Case { } } -#[derive(Diagnostic)] -#[diag("unknown `builtin #` construct `{$name}`")] -pub(crate) struct UnknownBuiltinConstruct { - #[primary_span] - pub span: Span, - pub name: Ident, -} - -#[derive(Diagnostic)] -#[diag("expected identifier after `builtin #`")] -pub(crate) struct ExpectedBuiltinIdent { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag("static items may not have generic parameters")] pub(crate) struct StaticWithGenerics { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 84aa391590041..e8c4ee4aae0f2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1315,8 +1315,6 @@ impl<'a> Parser<'a> { }) } else if this.check(exp!(OpenBracket)) { this.parse_expr_array_or_repeat(exp!(CloseBracket)) - } else if this.is_builtin() { - this.parse_expr_builtin() } else if this.check_path() { this.parse_expr_path_start() } else if this.token.is_keyword(kw::Move) @@ -1385,6 +1383,14 @@ impl<'a> Parser<'a> { return Ok(expr); } Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore)) + } else if this.eat_forced_keyword_noexpect(kw::OffsetOf) { + this.parse_expr_offset_of(lo) + } else if this.eat_forced_keyword_noexpect(kw::TypeAscribe) { + this.parse_expr_type_ascribe(lo) + } else if this.eat_forced_keyword_noexpect(kw::WrapBinder) { + this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap) + } else if this.eat_forced_keyword_noexpect(kw::UnwrapBinder) { + this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap) } else if this.token_uninterpolated_span().at_least_rust_2018() { // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly. let at_async = this.check_keyword(exp!(Async)); @@ -1826,58 +1832,9 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } - /// Parse `builtin # ident(args,*)`. - fn parse_expr_builtin(&mut self) -> PResult<'a, Box> { - self.parse_builtin(|this, lo, ident| { - Ok(match ident.name { - sym::offset_of => Some(this.parse_expr_offset_of(lo)?), - sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?), - sym::wrap_binder => { - Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?) - } - sym::unwrap_binder => { - Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?) - } - _ => None, - }) - }) - } - - pub(crate) fn parse_builtin( - &mut self, - parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option>, - ) -> PResult<'a, T> { - let lo = self.token.span; - - self.bump(); // `builtin` - self.bump(); // `#` - - let Some((ident, IdentKind::Normal)) = self.token.ident() else { - let err = self - .dcx() - .create_err(crate::diagnostics::ExpectedBuiltinIdent { span: self.token.span }); - return Err(err); - }; - self.psess.gated_spans.gate(sym::builtin_syntax, ident.span); - self.bump(); - + pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box> { self.expect(exp!(OpenParen))?; - let ret = if let Some(res) = parse(self, lo, ident)? { - Ok(res) - } else { - let err = self.dcx().create_err(crate::diagnostics::UnknownBuiltinConstruct { - span: lo.to(ident.span), - name: ident, - }); - return Err(err); - }; - self.expect(exp!(CloseParen))?; - - ret - } - /// Built-in macro for `offset_of!` expressions. - pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box> { let container = self.parse_ty()?; self.expect(exp!(Comma))?; @@ -1900,16 +1857,26 @@ impl<'a> Parser<'a> { } } + // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but + // it actually "improves" diagnostics slightly by not pointing into the wrapper macros. let span = lo.to(self.token.span); + self.expect(exp!(CloseParen))?; + + self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span)); + Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields))) } - /// Built-in macro for type ascription expressions. pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box> { + self.expect(exp!(OpenParen))?; let expr = self.parse_expr()?; self.expect(exp!(Comma))?; let ty = self.parse_ty()?; + // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but + // it actually "improves" diagnostics slightly by not pointing into the wrapper macros. let span = lo.to(self.token.span); + self.expect(exp!(CloseParen))?; + self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span)); Ok(self.mk_expr(span, ExprKind::Type(expr, ty))) } @@ -1918,9 +1885,15 @@ impl<'a> Parser<'a> { lo: Span, kind: UnsafeBinderCastKind, ) -> PResult<'a, Box> { + self.expect(exp!(OpenParen))?; + let expr = self.parse_expr()?; let ty = if self.eat(exp!(Comma)) { Some(self.parse_ty()?) } else { None }; + // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but + // it actually "improves" diagnostics slightly by not pointing into the wrapper macros. let span = lo.to(self.token.span); + self.expect(exp!(CloseParen))?; + self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span)); Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty))) } @@ -3423,10 +3396,6 @@ impl<'a> Parser<'a> { Ok(expr) } - pub(crate) fn is_builtin(&self) -> bool { - self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound) - } - /// Parses a `try {...}` or `try bikeshed Ty {...}` expression (`try` token already eaten). fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box> { let annotation = diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bc74ff14a1b3a..27646bac1c21e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -354,9 +354,6 @@ impl<'a> Parser<'a> { // UNION ITEM self.bump(); // `union` self.parse_item_union()? - } else if self.is_builtin() { - // BUILTIN# ITEM - return self.parse_item_builtin(); } else if self.eat_keyword_case(exp!(Macro), case) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? @@ -599,11 +596,6 @@ impl<'a> Parser<'a> { if let Some(err) = err { Err(self.dcx().create_err(err)) } else { Ok(()) } } - fn parse_item_builtin(&mut self) -> PResult<'a, Option> { - // To be expanded - Ok(None) - } - /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index fb26ef5e8ace6..a89fd9b6298f3 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -630,6 +630,15 @@ impl<'a> Parser<'a> { if !self.eat_keyword(exp) { self.unexpected() } else { Ok(()) } } + #[must_use] + pub(crate) fn eat_forced_keyword_noexpect(&mut self, kw: Symbol) -> bool { + if self.token.is_forced_keyword(kw) { + self.bump(); + return true; + } + false + } + /// Consume a sequence produced by a metavar expansion, if present. pub fn eat_metavar_seq( &mut self, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9fd38aa0f3b8f..422e3cbfd082e 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -801,8 +801,17 @@ impl<'a> Parser<'a> { } else { PatKind::Expr(const_expr) } - } else if self.is_builtin() { - self.parse_pat_builtin()? + } else if self.eat_forced_keyword_noexpect(kw::Deref) { + self.expect(exp!(OpenParen))?; + let pat = ast::PatKind::Deref(Box::new(self.parse_pat_allow_top_guard( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::LikelyTuple, + )?)); + self.expect(exp!(CloseParen))?; + self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span)); + pat } // Don't eagerly error on semantically invalid tokens when matching // declarative macros, as the input to those doesn't have to be @@ -1608,23 +1617,6 @@ impl<'a> Parser<'a> { .contains(&self.token.kind) } - fn parse_pat_builtin(&mut self) -> PResult<'a, PatKind> { - self.parse_builtin(|self_, _lo, ident| { - Ok(match ident.name { - // builtin#deref(PAT) - sym::deref => { - Some(ast::PatKind::Deref(Box::new(self_.parse_pat_allow_top_guard( - None, - RecoverComma::Yes, - RecoverColon::Yes, - CommaRecoveryMode::LikelyTuple, - )?))) - } - _ => None, - }) - }) - } - // FIXME: remove this entirely eventually /// Parses the removed `box pat` syntax to provide a more helpful error message. fn parse_pat_box(&mut self) -> PResult<'a, PatKind> { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 49bcdbbe8fa57..df2df24854ee1 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -126,11 +126,7 @@ impl<'a> Parser<'a> { diagnostics::InvalidVariableDeclarationSub::UseLetNotVar, force_collect, )? - } else if self.check_path() - && !self.token.is_qpath_start() - && !self.is_path_start_item() - && !self.is_builtin() - { + } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index e2187612f5d20..b66d7310dbea5 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -326,8 +326,6 @@ impl<'a> Parser<'a> { self.parse_borrowed_pointee()? } else if self.eat_keyword_noexpect(kw::Typeof) { self.parse_typeof_ty(lo)? - } else if self.is_builtin() { - self.parse_builtin_ty()? } else if self.eat_keyword(exp!(Underscore)) { // A type to be inferred `_` TyKind::Infer @@ -423,6 +421,8 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |tok| tok.kind == token::Lt) { self.parse_unsafe_binder_ty()? + } else if self.eat_forced_keyword_noexpect(kw::FieldOf) { + self.parse_ty_field_of(lo)? } else { let msg = format!("expected type, found {}", super::token_descr(&self.token)); let mut err = self.dcx().struct_span_err(lo, msg); @@ -826,16 +826,9 @@ impl<'a> Parser<'a> { Ok(TyKind::Err(guar)) } - fn parse_builtin_ty(&mut self) -> PResult<'a, TyKind> { - self.parse_builtin(|this, lo, ident| { - Ok(match ident.name { - sym::field_of => Some(this.parse_ty_field_of(lo)?), - _ => None, - }) - }) - } + pub(crate) fn parse_ty_field_of(&mut self, lo: Span) -> PResult<'a, TyKind> { + self.expect(exp!(OpenParen))?; - pub(crate) fn parse_ty_field_of(&mut self, _lo: Span) -> PResult<'a, TyKind> { let container = self.parse_ty()?; self.expect(exp!(Comma))?; @@ -844,30 +837,36 @@ impl<'a> Parser<'a> { if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) { if trailing_comma { - e.note("unexpected third argument to field_of"); + e.note("unexpected third argument to `field_of`"); } else { - e.note("field_of expects dot-separated field and variant names"); + e.note("`field_of` expects dot-separated field and variant names"); } e.emit(); } - // Eat tokens until the macro call ends. + // Eat tokens until the construct ends. if self.may_recover() { while !self.token.kind.is_close_delim_or_eof() { self.bump(); } } + // FIXME: Odd not to include the closing paren (contrary to the leading one etc.) but + // it actually "improves" diagnostics slightly by not pointing into the wrapper macros. + let span = self.token.span; + self.expect(exp!(CloseParen))?; + + self.psess.gated_spans.gate(sym::internal_syntax, lo.to(self.token.span)); + match *fields { - [] => Err(self.dcx().struct_span_err( - self.token.span, - "`field_of!` expects dot-separated field and variant names", - )), + [] => Err(self + .dcx() + .struct_span_err(span, "`field_of` expects dot-separated field and variant names")), [field] => Ok(TyKind::FieldOf(container, None, field)), [variant, field] => Ok(TyKind::FieldOf(container, Some(variant), field)), _ => Err(self.dcx().struct_span_err( fields.iter().map(|f| f.span).collect::>(), - "`field_of!` only supports a single field or a variant with a field", + "`field_of` only supports a single field or a variant with a field", )), } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6f078fef4892b..6c0a9cab34f8e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -125,17 +125,22 @@ symbols! { // Matching predicates: `is_weak` // tidy-alphabetical-start Auto: "auto", - Builtin: "builtin", Catch: "catch", ContractEnsures: "contract_ensures", ContractRequires: "contract_requires", Default: "default", + Deref: "deref", + FieldOf: "field_of", MacroRules: "macro_rules", + OffsetOf: "offset_of", Pin: "pin", Raw: "raw", Reuse: "reuse", Safe: "safe", + TypeAscribe: "type_ascribe", Union: "union", + UnwrapBinder: "unwrap_binder", + WrapBinder: "wrap_binder", Yeet: "yeet", // tidy-alphabetical-end } @@ -580,7 +585,6 @@ symbols! { bridge, bswap, built, - builtin_syntax, bundle, c_dash_variadic, c_str_literals, @@ -828,7 +832,6 @@ symbols! { deprecated, deprecated_safe, deprecated_suggestion, - deref, deref_method, deref_mut, deref_patterns, @@ -990,7 +993,6 @@ symbols! { field, field_base, field_init_shorthand, - field_of, field_offset, field_projections, field_representing_type, @@ -1173,6 +1175,7 @@ symbols! { integral, internal_eq_trait_method_impls, internal_features, + internal_syntax, interrupt, into_async_iter_into_iter, into_future, @@ -1507,7 +1510,6 @@ symbols! { offload_kernel, offload_region, offset, - offset_of, offset_of_enum, offset_of_nested, offset_of_slice, @@ -2204,7 +2206,6 @@ symbols! { ty, type_alias_enum_variants, type_alias_impl_trait, - type_ascribe, type_ascription, type_changing_struct_update, type_id, @@ -2333,7 +2334,6 @@ symbols! { unwind_attributes, unwind_safe_trait, unwrap, - unwrap_binder, unwrap_or, update, use_cloned, @@ -2419,7 +2419,6 @@ symbols! { windows, windows_subsystem, with_negative_coherence, - wrap_binder, wrapping_add, wrapping_div, wrapping_mul, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index a0e1267ed16e1..d4ff3af28ed7f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -66,8 +66,8 @@ use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt}; use rustc_middle::ty::print::{PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths}; use rustc_middle::ty::{ - self, List, Mutability, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, Unnormalized, + self, IsRigid, List, Mutability, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, Unnormalized, }; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, bug, sym}; use thin_vec::ThinVec; @@ -2479,6 +2479,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. + /// Non-rigid aliases are treated just like TyVar since normalization can be ambiguous here. pub fn same_type_modulo_infer>>(&self, a: T, b: T) -> bool { let (a, b) = self.deeply_resolve_ignoring_regions((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() @@ -2528,7 +2529,9 @@ impl<'tcx> TypeRelation> for SameTypeModuloInfer<'_, 'tcx> { ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)), ) | (ty::Infer(ty::InferTy::TyVar(_)), _) - | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), + | (_, ty::Infer(ty::InferTy::TyVar(_))) + | (ty::Alias(IsRigid::No, _), _) + | (_, ty::Alias(IsRigid::No, _)) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), _ => relate::structurally_relate_tys(self, a, b), } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index c55c43e18d2bf..be07ff71ccf34 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -33,7 +33,7 @@ use thin_vec::{ThinVec, thin_vec}; use super::inspect::InferCtxtProofTreeExt; use crate::solve::inspect::{self, InspectConfig, ProofTreeVisitor}; -use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; +use crate::traits::{EvaluateConstErr, ObligationCause, implicit_fast_path, specialization_graph}; #[repr(transparent)] pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); @@ -178,7 +178,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) | Some(LangItem::MetaSized) => { let predicate = self.deeply_resolve_ignoring_regions(goal.predicate); - if sizedness_fast_path(self.tcx, predicate, goal.param_env) { + if implicit_fast_path(self.tcx, predicate, goal.param_env) { Outcome::TriviallyHolds } else { Outcome::NoFastPath diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 3a1ad2ee5feab..56e80958e6892 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -33,7 +33,7 @@ use crate::infer::InferCtxt; use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{EvaluateConstErr, sizedness_fast_path}; +use crate::traits::{EvaluateConstErr, implicit_fast_path}; pub(crate) type PendingPredicateObligations<'tcx> = ThinVec>; @@ -398,7 +398,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx; if !infcx.disable_trait_solver_fast_paths() - && sizedness_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) + && implicit_fast_path(infcx.tcx, obligation.predicate, obligation.param_env) { return ProcessResult::Changed(thin_vec![]); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 7076ec99c141c..326710007564c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -66,7 +66,7 @@ pub use self::specialize::{ pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::{ BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final, - sizedness_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, + implicit_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars, }; use crate::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 148f75e0a6308..b8c2a3078e8cb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; use crate::infer::InferCtxt; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; -use crate::traits::{ObligationCtxt, sizedness_fast_path}; +use crate::traits::{ObligationCtxt, implicit_fast_path}; impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { type QueryResponse = (); @@ -15,7 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { infcx: &InferCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - if sizedness_fast_path(infcx.tcx, key.value.predicate, key.param_env) { + if implicit_fast_path(infcx.tcx, key.value.predicate, key.param_env) { return Some(()); } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 8a770bea8468b..0d497fe86cf44 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -15,8 +15,8 @@ use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{ - self, ExistentialPredicate, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, - elaborate, + self, ExistentialPredicate, FieldInfo, IncludeSizedImplicitBounds, SizedTraitKind, TraitRef, + Ty, TypeVisitableExt, elaborate, }; use rustc_span::{DUMMY_SP, bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -782,7 +782,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Backward compatibility for default auto traits. // Test: ui/traits/default_auto_traits/extern-types.rs - if self.tcx().is_default_trait(def_id) { + if self.tcx().is_implicit_trait(def_id, IncludeSizedImplicitBounds::No) { check_impls() } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e280184169844..279392221a33c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -47,7 +47,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; -use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, sizedness_fast_path}; +use crate::traits::{EvaluateConstErr, ProjectionCacheKey, effects, implicit_fast_path}; mod _match; mod candidate_assembly; @@ -537,7 +537,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if !self.infcx.disable_trait_solver_fast_paths() - && sizedness_fast_path(self.tcx(), obligation.predicate, obligation.param_env) + && implicit_fast_path(self.tcx(), obligation.predicate, obligation.param_env) { return Ok(EvaluatedToOk); } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c60ebc4758ead..9cbb53c6f63bd 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -217,7 +217,7 @@ pub fn with_replaced_escaping_bound_vars< } } -pub fn sizedness_fast_path<'tcx>( +pub fn implicit_fast_path<'tcx>( tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 6bc6543a0a01b..ac5df8b93f482 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -5,7 +5,7 @@ use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; use rustc_trait_selection::traits::{ EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, - sizedness_fast_path, + implicit_fast_path, }; use tracing::debug; @@ -24,7 +24,7 @@ fn evaluate_obligation<'tcx>( debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; - if !tcx.disable_trait_solver_fast_paths() && sizedness_fast_path(tcx, predicate, param_env) { + if !tcx.disable_trait_solver_fast_paths() && implicit_fast_path(tcx, predicate, param_env) { return Ok(EvaluationResult::EvaluatedToOk); } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 7aa3d87328fe7..edcc0082a942f 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -317,7 +317,7 @@ pub struct CanonicalParamEnvCacheEntry { pub param_env: I::ParamEnv, pub variables: Vec, pub variable_lookup_table: HashMap, - pub var_kinds: Vec>, + pub var_kinds: I::CanonicalVarKinds, } /// State used and modified by a canonicalizer during canonicalization. To avoid many allocations, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index be0114b8f3af3..4de18651b3520 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -461,6 +461,12 @@ pub trait Interner: fn is_default_trait(self, def_id: Self::TraitId) -> bool; + fn is_implicit_trait( + self, + def_id: Self::TraitId, + including_sized: IncludeSizedImplicitBounds, + ) -> bool; + fn is_sizedness_trait(self, def_id: Self::TraitId) -> bool; fn as_projection_lang_item( @@ -786,3 +792,8 @@ impl search_graph::Cx for I { self.assert_evaluation_is_concurrent() } } + +pub enum IncludeSizedImplicitBounds { + Yes, + No, +} diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 53afc311cc623..e300b94cbc438 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -461,9 +461,8 @@ pub enum CandidatePreferenceMode { impl CandidatePreferenceMode { /// Given `trait_def_id`, which candidate preference mode should be used? pub fn compute(cx: I, trait_id: I::TraitId) -> CandidatePreferenceMode { - let is_sizedness_or_auto_or_default_goal = cx.is_sizedness_trait(trait_id) - || cx.trait_is_auto(trait_id) - || cx.is_default_trait(trait_id); + let is_sizedness_or_auto_or_default_goal = cx.trait_is_auto(trait_id) + || cx.is_implicit_trait(trait_id, ty::IncludeSizedImplicitBounds::Yes); if is_sizedness_or_auto_or_default_goal { CandidatePreferenceMode::Marker } else { diff --git a/library/core/src/field.rs b/library/core/src/field.rs index 5a8ae7759bc1e..b17a78846ce2a 100644 --- a/library/core/src/field.rs +++ b/library/core/src/field.rs @@ -124,7 +124,7 @@ impl Ord /// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the /// variant must also be specified. Only a single field is supported. #[unstable(feature = "field_projections", issue = "145383")] -#[allow_internal_unstable(field_representing_type_raw, builtin_syntax)] +#[allow_internal_unstable(field_representing_type_raw, internal_syntax)] #[diagnostic::on_unmatched_args( note = "this macro expects a container type and a field path, like `field_of!(Type, field)` or `field_of!(Enum, Variant.field)`" )] @@ -134,7 +134,7 @@ impl Ord // it to `FieldRepresentingType<...>`. Thus stabilizing this requires careful thought about the // completeness of the trait impls for `FieldRepresentingType`. pub macro field_of($Container:ty, $($fields:expr)+ $(,)?) { - builtin # field_of($Container, $($fields)+) + k#field_of($Container, $($fields)+) } /// Type representing a field of a `struct`, `union`, `enum` variant or tuple. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 36a19f89e58cd..67c216053f7b1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -129,6 +129,7 @@ #![feature(f128)] #![feature(field_projections)] #![feature(final_associated_functions)] +#![feature(forced_keywords)] #![feature(freeze_impls)] #![feature(fundamental)] #![feature(impl_restriction)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3b378078d3284..789119fb20052 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1907,7 +1907,7 @@ pub(crate) mod builtin { } /// Unstable placeholder for type ascription. - #[allow_internal_unstable(builtin_syntax)] + #[allow_internal_unstable(internal_syntax)] #[unstable( feature = "type_ascription", issue = "101728", @@ -1915,11 +1915,11 @@ pub(crate) mod builtin { )] #[diagnostic::opaque] pub macro type_ascribe($expr:expr, $ty:ty) { - builtin # type_ascribe($expr, $ty) + k#type_ascribe($expr, $ty) } /// Unstable placeholder for deref patterns. - #[allow_internal_unstable(builtin_syntax)] + #[allow_internal_unstable(internal_syntax)] #[unstable( feature = "deref_patterns", issue = "87121", @@ -1927,7 +1927,7 @@ pub(crate) mod builtin { )] #[diagnostic::opaque] pub macro deref($pat:pat) { - builtin # deref($pat) + k#deref($pat) } /// Derive macro generating an impl of the trait `From`. diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index b38557779092c..39b07963fb9a9 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1664,10 +1664,10 @@ impl SizedTypeProperties for T {} note = "this macro expects a container type and a (nested) field path, like `offset_of!(Type, field)`" )] #[doc(alias = "memoffset")] -#[allow_internal_unstable(builtin_syntax, core_intrinsics)] +#[allow_internal_unstable(core_intrinsics, internal_syntax)] #[diagnostic::opaque] pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { - const { builtin # offset_of($Container, $($fields)+) } + const { k#offset_of($Container, $($fields)+) } } /// Create a fresh instance of the inhabited ZST type `T`. diff --git a/library/core/src/unsafe_binder.rs b/library/core/src/unsafe_binder.rs index 3d2a04e95f078..bb7144fc5dddd 100644 --- a/library/core/src/unsafe_binder.rs +++ b/library/core/src/unsafe_binder.rs @@ -1,27 +1,17 @@ //! Operators used to turn types into unsafe binders and back. /// Unwrap an unsafe binder into its underlying type. -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(internal_syntax)] #[unstable(feature = "unsafe_binders", issue = "130516")] #[diagnostic::opaque] -pub macro unwrap_binder { - ($expr:expr) => { - builtin # unwrap_binder ( $expr ) - }, - ($expr:expr ; $ty:ty) => { - builtin # unwrap_binder ( $expr, $ty ) - }, +pub macro unwrap_binder($expr:expr $( ; $ty:ty )?) { + k#unwrap_binder($expr $( , $ty )?) } /// Wrap a type into an unsafe binder. -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(internal_syntax)] #[unstable(feature = "unsafe_binders", issue = "130516")] #[diagnostic::opaque] -pub macro wrap_binder { - ($expr:expr) => { - builtin # wrap_binder ( $expr ) - }, - ($expr:expr ; $ty:ty) => { - builtin # wrap_binder ( $expr, $ty ) - }, +pub macro wrap_binder($expr:expr $( ; $ty:ty )?) { + k#wrap_binder($expr $( , $ty )?) } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8ed3a46bf3189..cd3fc8fda587b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -287,7 +287,6 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(exact_div)] #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index cee799c36c79b..756c5ec26f127 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -253,37 +253,14 @@ pub fn current_exe() -> io::Result { #[cfg(target_os = "openbsd")] pub fn current_exe() -> io::Result { + let mut path = vec![0u8; libc::PATH_MAX as usize]; unsafe { - let mut mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, libc::getpid(), libc::KERN_PROC_ARGV]; - let mib = mib.as_mut_ptr(); - - // Determine the required size (in bytes) for the argument array ... - let mut argv_size = 0; - cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_size, ptr::null_mut(), 0))?; - - // ... allocate a buffer for it ... - let argc = argv_size.div_exact(size_of::<*const libc::c_char>()).unwrap(); - let mut argv = Vec::<*const libc::c_char>::with_capacity(argc); - - // ... and retrieve the argument array. - cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_size, ptr::null_mut(), 0))?; - let argc = argv_size.div_exact(size_of::<*const libc::c_char>()).unwrap(); - argv.set_len(argc); - - if argv[0].is_null() { - return Err(io::const_error!(io::ErrorKind::Uncategorized, "no current exe available")); - } - let argv0 = CStr::from_ptr(argv[0]).to_bytes(); - if argv0.iter().any(|b| *b == b'/') { - // The program name is path-like, so try to canonicalize it. - crate::fs::canonicalize(OsStr::from_bytes(argv0)) - } else { - // The program was probably found in the PATH. Instead of trying to - // find it again (which might not succeed if PATH has changed), just - // return the program name – this function is best-effort anyway. - Ok(PathBuf::from(OsStr::from_bytes(argv0))) - } + cvt(libc::getexecpath(path.as_mut_ptr().cast(), path.len()))?; + // SAFETY: getexecpath(3) NUL-terminates the buffer on success. + let len = CStr::from_ptr(path.as_ptr().cast()).count_bytes(); + path.truncate(len); } + Ok(PathBuf::from(OsString::from_vec(path))) } #[cfg(any( diff --git a/library/std/src/sys/thread_local/guard/aix.rs b/library/std/src/sys/thread_local/guard/aix.rs new file mode 100644 index 0000000000000..9b945456bf790 --- /dev/null +++ b/library/std/src/sys/thread_local/guard/aix.rs @@ -0,0 +1,30 @@ +//! AIX registers thread destructors using `__pt_atexit_np`. +//! Calling it registers a callback that runs on thread termination +//! and upon process exit (for the main thread). + +use crate::cell::Cell; +use crate::sys::thread_local::destructors; + +pub fn enable() { + #[thread_local] + static REGISTERED: Cell = Cell::new(false); + + unsafe extern "C" { + fn __pt_atexit_np(flags: i32, dtor: unsafe extern "C" fn(i32) -> i32) -> i32; + } + + if !REGISTERED.replace(true) { + let ret = unsafe { __pt_atexit_np(0, run_dtors) }; + if ret != 0 { + rtabort!("failed to register thread destructor"); + } + } + + unsafe extern "C" fn run_dtors(_: i32) -> i32 { + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } + 0 + } +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 5d3c23ce04678..1c137e52d9319 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -101,6 +101,10 @@ pub(crate) mod guard { mod apple; pub(crate) use apple::enable; } + all(target_thread_local, target_os = "aix") => { + mod aix; + pub(crate) use aix::enable; + } target_os = "windows" => { mod windows; pub(crate) use windows::enable; diff --git a/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile index d248faaabca6c..2a721006bfdc0 100644 --- a/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/test-x86_64-gnu-gcc/Dockerfile @@ -42,7 +42,7 @@ ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --set llvm.libzstd=true" ENV SCRIPT="python3 ../x.py \ --stage 2 \ - test tests \ + test tests compiler/rustc_codegen_gcc \ --test-codegen-backend gcc \ --skip tests/coverage \ --skip tests/coverage-run-rustdoc \ diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index dd5e307fdfca5..2dcf3d51fc509 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1821,7 +1821,7 @@ impl PrimitiveType { Char => sym::char, Array => sym::array, Pat => sym::pat, - FieldOf => sym::field_of, + FieldOf => kw::FieldOf, Slice => sym::slice, Tuple => sym::tuple, Unit => sym::unit, diff --git a/src/tools/clippy/clippy_lints/src/methods/should_implement_trait.rs b/src/tools/clippy/clippy_lints/src/methods/should_implement_trait.rs index c233fe3f28ed5..2536ad574239b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/should_implement_trait.rs +++ b/src/tools/clippy/clippy_lints/src/methods/should_implement_trait.rs @@ -112,7 +112,7 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [ ShouldImplTraitCase::new("std::clone::Clone", sym::clone, 1, SelfKind::Ref, OutType::Any, true, Edition2015), ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp, 2, SelfKind::Ref, OutType::Any, true, Edition2015), ShouldImplTraitCase::new("std::default::Default", kw::Default, 0, SelfKind::No, OutType::Any, true, Edition2015), - ShouldImplTraitCase::new("std::ops::Deref", sym::deref, 1, SelfKind::Ref, OutType::Ref, true, Edition2015), + ShouldImplTraitCase::new("std::ops::Deref", kw::Deref, 1, SelfKind::Ref, OutType::Ref, true, Edition2015), ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut, 1, SelfKind::RefMut, OutType::Ref, true, Edition2015), ShouldImplTraitCase::new("std::ops::Div", sym::div, 2, SelfKind::Value, OutType::Any, true, Edition2015), ShouldImplTraitCase::new("std::ops::Drop", sym::drop, 1, SelfKind::RefMut, OutType::Unit, true, Edition2015), diff --git a/src/tools/rustfmt/.github/workflows/check_diff.yml b/src/tools/rustfmt/.github/workflows/check_diff.yml index b3543a49c3e9b..7f7bc62846a3c 100644 --- a/src/tools/rustfmt/.github/workflows/check_diff.yml +++ b/src/tools/rustfmt/.github/workflows/check_diff.yml @@ -51,6 +51,8 @@ jobs: steps: - name: checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Build check_diff binary working-directory: ./check_diff @@ -60,19 +62,25 @@ jobs: working-directory: ./check_diff env: CHECK_DIFF_LOG: info + GITHUB_EVENT_INPUTS_COMMIT_HASH: ${{ github.event.inputs.commit_hash }} + GITHUB_EVENT_INPUTS_RUSTFMT_CONFIGS: ${{ github.event.inputs.rustfmt_configs }} + GITHUB_EVENT_INPUTS_CLONE_URL: ${{ github.event.inputs.clone_url }} + GITHUB_EVENT_INPUTS_BRANCH_NAME: ${{ github.event.inputs.branch_name }} + GITHUB_EVENT_INPUTS_LANGUAGE_EDITION: ${{ github.event.inputs.language_edition }} + GITHUB_EVENT_INPUTS_STYLE_EDITION: ${{ github.event.inputs.style_edition }} shell: bash run: | OPTIONS="" - if [[ -n "${{ github.event.inputs.commit_hash }}" ]]; then - OPTIONS+="--commit-hash ${{ github.event.inputs.commit_hash }} " + if [[ -n "${GITHUB_EVENT_INPUTS_COMMIT_HASH}" ]]; then + OPTIONS+="--commit-hash ${GITHUB_EVENT_INPUTS_COMMIT_HASH} " fi - if [[ -n "${{ github.event.inputs.rustfmt_configs }}" ]]; then - OPTIONS+="--rustfmt-config ${{ github.event.inputs.rustfmt_configs }} " + if [[ -n "${GITHUB_EVENT_INPUTS_RUSTFMT_CONFIGS}" ]]; then + OPTIONS+="--rustfmt-config ${GITHUB_EVENT_INPUTS_RUSTFMT_CONFIGS} " fi - target/release/check_diff ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} \ - --edition ${{ github.event.inputs.language_edition }} \ - --style-edition ${{ github.event.inputs.style_edition }} \ + target/release/check_diff ${GITHUB_EVENT_INPUTS_CLONE_URL} ${GITHUB_EVENT_INPUTS_BRANCH_NAME} \ + --edition ${GITHUB_EVENT_INPUTS_LANGUAGE_EDITION} \ + --style-edition ${GITHUB_EVENT_INPUTS_STYLE_EDITION} \ $OPTIONS diff --git a/src/tools/rustfmt/.github/workflows/clippy.yml b/src/tools/rustfmt/.github/workflows/clippy.yml index a5aa91346dd84..fc3eb8916a6bd 100644 --- a/src/tools/rustfmt/.github/workflows/clippy.yml +++ b/src/tools/rustfmt/.github/workflows/clippy.yml @@ -13,6 +13,8 @@ jobs: steps: - name: checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: install rustup run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh @@ -35,10 +37,14 @@ jobs: steps: - name: checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: install rustup run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh sh rustup-init.sh -y --default-toolchain none - name: clippy - run: cargo clippy --locked --manifest-path ${{ matrix.package }}/Cargo.toml + run: cargo clippy --locked --manifest-path "${MATRIX_PACKAGE}/Cargo.toml" + env: + MATRIX_PACKAGE: ${{ matrix.package }} diff --git a/src/tools/rustfmt/.github/workflows/integration.yml b/src/tools/rustfmt/.github/workflows/integration.yml index 224605740e55e..e8da0d8d3aed1 100644 --- a/src/tools/rustfmt/.github/workflows/integration.yml +++ b/src/tools/rustfmt/.github/workflows/integration.yml @@ -60,6 +60,8 @@ jobs: steps: - name: checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Run build - name: install rustup @@ -70,5 +72,6 @@ jobs: - name: run integration tests env: TARGET: x86_64-unknown-linux-gnu - run: cargo run --locked --manifest-path ci/Cargo.toml integration ${{ matrix.integration }} + MATRIX_INTEGRATION: ${{ matrix.integration }} + run: cargo run --locked --manifest-path ci/Cargo.toml integration ${MATRIX_INTEGRATION} continue-on-error: ${{ matrix.allow-failure == true }} diff --git a/src/tools/rustfmt/.github/workflows/rustdoc_check.yml b/src/tools/rustfmt/.github/workflows/rustdoc_check.yml index b3978005fdf62..e2b5e5a68ed71 100644 --- a/src/tools/rustfmt/.github/workflows/rustdoc_check.yml +++ b/src/tools/rustfmt/.github/workflows/rustdoc_check.yml @@ -13,6 +13,8 @@ jobs: steps: - name: checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: install rustup run: | diff --git a/src/tools/rustfmt/.github/workflows/test.yml b/src/tools/rustfmt/.github/workflows/test.yml index 6d0f25834e596..44d36898f216f 100644 --- a/src/tools/rustfmt/.github/workflows/test.yml +++ b/src/tools/rustfmt/.github/workflows/test.yml @@ -43,6 +43,8 @@ jobs: run: git config --global core.autocrlf false - name: checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Rustup using win.rustup.rs if: ${{ matrix.os == 'windows-latest' }} @@ -52,7 +54,9 @@ jobs: Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe .\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none del rustup-init.exe - rustup target add ${{ matrix.target }} + rustup target add ${env:MATRIX_TARGET} + env: + MATRIX_TARGET: ${{ matrix.target }} shell: powershell - name: Add mingw32 to path for i686-gnu @@ -71,7 +75,9 @@ jobs: run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh sh rustup-init.sh -y --default-toolchain none - rustup target add ${{ matrix.target }} + rustup target add ${MATRIX_TARGET} + env: + MATRIX_TARGET: ${{ matrix.target }} # Run build - name: Build and Test @@ -97,6 +103,8 @@ jobs: - name: Conclusion run: | # Print the dependent jobs to see them in the CI log - jq -C <<< '${{ toJson(needs) }}' + jq -C <<< "${JSON_NEEDS}" # Check if all jobs that we depend on (in the needs array) were successful (or have been skipped). - jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}' + jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< "${JSON_NEEDS}" + env: + JSON_NEEDS: ${{ toJson(needs) }} diff --git a/src/tools/rustfmt/.github/workflows/upload-assets.yml b/src/tools/rustfmt/.github/workflows/upload-assets.yml deleted file mode 100644 index 991cc965e3d51..0000000000000 --- a/src/tools/rustfmt/.github/workflows/upload-assets.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: upload - -on: - push: - release: - types: [created] - workflow_dispatch: - -jobs: - build-release: - name: build-release - strategy: - matrix: - build: [linux-x86_64, macos-x86_64, windows-x86_64-gnu, windows-x86_64-msvc] - include: - - build: linux-x86_64 - os: ubuntu-latest - rust: nightly - target: x86_64-unknown-linux-gnu - - build: macos-x86_64 - os: macos-latest - rust: nightly - target: x86_64-apple-darwin - - build: windows-x86_64-gnu - os: windows-latest - rust: nightly-x86_64-gnu - target: x86_64-pc-windows-gnu - - build: windows-x86_64-msvc - os: windows-latest - rust: nightly-x86_64-msvc - target: x86_64-pc-windows-msvc - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - # Run build - - name: install rustup - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh - sh rustup-init.sh -y --default-toolchain none - rustup target add ${{ matrix.target }} - - - name: Add mingw64 to path for x86_64-gnu - run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH - if: matrix.rust == 'nightly-x86_64-gnu' - shell: bash - - - name: Build release binaries - run: cargo build --release --locked - - - name: Build archive - shell: bash - run: | - staging="rustfmt_${{ matrix.build }}_${{ github.event.release.tag_name }}" - mkdir -p "$staging" - - cp {README.md,Configurations.md,CHANGELOG.md,LICENSE-MIT,LICENSE-APACHE} "$staging/" - - if [ "${{ matrix.os }}" = "windows-latest" ]; then - cp target/release/{rustfmt.exe,cargo-fmt.exe,rustfmt-format-diff.exe,git-rustfmt.exe} "$staging/" - 7z a "$staging.zip" "$staging" - echo "ASSET=$staging.zip" >> $GITHUB_ENV - else - cp target/release/{rustfmt,cargo-fmt,rustfmt-format-diff,git-rustfmt} "$staging/" - tar czf "$staging.tar.gz" "$staging" - echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV - fi - - - name: Upload Release Asset - if: github.event_name == 'release' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh release upload "${{ github.event.release.tag_name }}" "${{ env.ASSET }}" diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md index 454ffc1a91cca..b28723aa08e5f 100644 --- a/src/tools/rustfmt/CHANGELOG.md +++ b/src/tools/rustfmt/CHANGELOG.md @@ -2,9 +2,34 @@ ## [Unreleased] -### Changed -- The unstable `required_version` configuration option now defaults to a caret (`^`) semver requirement instead of an exact match when no comparator is given, matching how Cargo treats dependency version requirements. Use the explicit `=` operator (e.g. `required_version = "=1.2.3"`) to opt back into exact matching [#6729](https://github.com/rust-lang/rustfmt/issues/6729) + +## [1.12.0] 2026-12-24 +### Changed +- The unstable `required_version` configuration option now defaults to a caret (`^`) semver requirement instead of an exact match when no comparator is given, matching how Cargo treats dependency version requirements. Use the explicit `=` operator (e.g. `required_version = "=1.2.3"`) to opt back into exact matching [#6729](https://github.com/rust-lang/rustfmt/issues/6729) [#7048](https://github.com/rust-lang/rustfmt/pull/7048) +> [!IMPORTANT] +> Potential breaking changes: +> - When `--config-path` is a directory, rustfmt now also searches its parent directories for config files [#4660](https://github.com/rust-lang/rustfmt/issues/4660) [#7115](https://github.com/rust-lang/rustfmt/pull/7115) +> - Chains with comments now format under `use_try_shorthand=true` [#6121](https://github.com/rust-lang/rustfmt/issues/6121) [#7095](https://github.com/rust-lang/rustfmt/pull/7095) +> - Error on `--print-config minimal` with no output path [#7208](https://github.com/rust-lang/rustfmt/pull/7208) +> - Previously, this printed a warning and exited with `0`. + +### Fixed +- Fix ragged statement comment wrapping under unstable option `wrap_comments=true` and `comment_width` [#7167](https://github.com/rust-lang/rustfmt/issues/7167) [#7170](https://github.com/rust-lang/rustfmt/pull/7170) +- Enforce comment width in item lists [#7174](https://github.com/rust-lang/rustfmt/pull/7174) +- Fix lookup of global config files [#7178](https://github.com/rust-lang/rustfmt/issues/7178) [#7179](https://github.com/rust-lang/rustfmt/pull/7179) +- Don't remove empty generic args when formatting in a macro context [#7136](https://github.com/rust-lang/rustfmt/issues/7136) [#7181](https://github.com/rust-lang/rustfmt/pull/7181) +- Various `cfg_select!` fixes. Note that `cfg_select!` formatting is still nightly-gated. + - Fix `cfg_select!` parser recovery handling and error count leak [#7171](https://github.com/rust-lang/rustfmt/pull/7171) + - Don't remove necessary blocks when formatting `cfg_select!` arms [#7045](https://github.com/rust-lang/rustfmt/issues/7045) [#7183](https://github.com/rust-lang/rustfmt/pull/7183) + - Prevent more comment loss in `cfg_select!` [#7209](https://github.com/rust-lang/rustfmt/issues/7209) [rust-lang/rust#164815](https://github.com/rust-lang/rust/pull/164815) + - Don't lose comments and attributes between `cfg_select!` predicates, outer/inner blocks, arm body and trailing commas [#7209](https://github.com/rust-lang/rustfmt/issues/7209) [#7211](https://github.com/rust-lang/rustfmt/pull/7211) + - Have `cfg_select!` double-brace concise formatting respect `control_brace_style` unstable option [#7214](https://github.com/rust-lang/rustfmt/pull/7214) +- Prevent rustfmt from removing expression attributes when removing nested parentheses [#7190](https://github.com/rust-lang/rustfmt/issues/7190) [#7192](https://github.com/rust-lang/rustfmt/pull/7192) +- Fix `cfg_if!` error count leaks [#7195](https://github.com/rust-lang/rustfmt/pull/7195) +- Format comments after `where` clauses using `clause_shape` budget (affecting unstable options `wrap_comments=true` and `comment_width`) [#7148](https://github.com/rust-lang/rustfmt/issues/7148) [#7156](https://github.com/rust-lang/rustfmt/pull/7156) +- Fix ICE on failure to format generics in enum [#5738](https://github.com/rust-lang/rustfmt/issues/5738) [#6137](https://github.com/rust-lang/rustfmt/issues/6137) [#6318](https://github.com/rust-lang/rustfmt/issues/6318) [#6646](https://github.com/rust-lang/rustfmt/issues/6646) [#6396](https://github.com/rust-lang/rustfmt/pull/6396) +- Avoid leaking wrapper space from doc comment code block formatting (affecting unstable options `format_code_in_doc_comments=true` and `fn_single_line=true`) [#6832](https://github.com/rust-lang/rustfmt/issues/6832) [#6851](https://github.com/rust-lang/rustfmt/pull/6851) ## [1.11.0] 2026-11-12 @@ -28,7 +53,6 @@ - Correct visibility and defaultness order on associated impl type alias [#7064](https://github.com/rust-lang/rustfmt/pull/7064). - Correctly calculate the `shape` for inline const blocks when using `style_edition=2027` [#7065](https://github.com/rust-lang/rustfmt/pull/7065). - Prevent invalid code generation in macros that use raw identifiers [#7110](https://github.com/rust-lang/rustfmt/pull/7110). -- Prevent rustfmt from reporting on `max_width` configuration issues when formatting macros [#6651](https://github.com/rust-lang/rustfmt/pull/6651). ### Changed - No longer apply `use_field_init_shorthand` when formatting macros [#6981](https://github.com/rust-lang/rustfmt/pull/6981). diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index b83c8ec9612c5..38d5f7724e84d 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -582,7 +582,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.11.0" +version = "1.12.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 9e689fc0041f1..78ee1fb2742a0 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustfmt-nightly" -version = "1.11.0" +version = "1.12.0" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" license = "Apache-2.0 OR MIT" diff --git a/src/tools/rustfmt/rust-toolchain.toml b/src/tools/rustfmt/rust-toolchain.toml index d621e4fb08484..0a85b69efd3e9 100644 --- a/src/tools/rustfmt/rust-toolchain.toml +++ b/src/tools/rustfmt/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-10-22" +channel = "nightly-2026-11-02" components = ["llvm-tools", "rustc-dev"] diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 7b003672795bd..0653ad3d93758 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -93,12 +93,6 @@ pub enum OperationError { /// An unknown help topic was requested. #[error("Unknown help topic: `{0}`.")] UnknownHelpTopic(String), - /// An unknown print-config option was requested. - #[error("Unknown print-config option: `{0}`.")] - UnknownPrintConfigTopic(String), - /// Attempt to generate a minimal config from standard input. - #[error("The `--print-config=minimal` option doesn't work with standard input.")] - MinimalPathWithStdin, /// An io error during reading or writing. #[error("{0}")] IoError(IoError), @@ -106,6 +100,21 @@ pub enum OperationError { /// supported with standard input. #[error("Emit mode {0} not supported with standard output.")] StdinBadEmit(EmitMode), + #[error(transparent)] + PrintConfig(PrintConfigError), +} + +// Errors related to the '--print-config' option. +#[derive(Error, Debug)] +pub enum PrintConfigError { + /// An unknown print-config option was requested. + #[error("Unknown print-config option: `{0}`.")] + UnknownOption(String), + #[error("The `--print-config=minimal` option requires an output path to write to")] + MinimalPathNoPath, + /// Attempt to generate a minimal config from standard input. + #[error("The `--print-config=minimal` option doesn't work with standard input.")] + MinimalPathWithStdin, } impl From for OperationError { @@ -490,23 +499,24 @@ fn determine_operation(matches: &Matches) -> Result { } let mut free_matches = matches.free.iter(); - let mut minimal_config_path = None; - if let Some(kind) = matches.opt_str("print-config") { - let path = free_matches.next().cloned(); - match kind.as_str() { - "default" => return Ok(Operation::ConfigOutputDefault { path }), - "current" => return Ok(Operation::ConfigOutputCurrent { path }), - "minimal" => { - minimal_config_path = path; - if minimal_config_path.is_none() { - eprintln!("WARNING: PATH required for `--print-config minimal`."); + let minimal_config_path = match matches.opt_str("print-config") { + None => None, + Some(kind) => { + let path = free_matches.next().cloned(); + match kind.as_str() { + "default" => return Ok(Operation::ConfigOutputDefault { path }), + "current" => return Ok(Operation::ConfigOutputCurrent { path }), + "minimal" => Some(path.ok_or(OperationError::PrintConfig( + PrintConfigError::MinimalPathNoPath, + ))?), + _ => { + return Err(OperationError::PrintConfig( + PrintConfigError::UnknownOption(kind), + )); } } - _ => { - return Err(OperationError::UnknownPrintConfigTopic(kind)); - } } - } + }; if matches.opt_present("version") { return Ok(Operation::Version); @@ -524,7 +534,9 @@ fn determine_operation(matches: &Matches) -> Result { // if no file argument is supplied, read from stdin if files.is_empty() { if minimal_config_path.is_some() { - return Err(OperationError::MinimalPathWithStdin); + return Err(OperationError::PrintConfig( + PrintConfigError::MinimalPathWithStdin, + )); } let mut buffer = String::new(); io::stdin().read_to_string(&mut buffer)?; diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs index ee1ccdb437801..69749feb0f357 100644 --- a/src/tools/rustfmt/src/config/config_type.rs +++ b/src/tools/rustfmt/src/config/config_type.rs @@ -435,65 +435,6 @@ macro_rules! create_config { )+ } - /// Reduces the maximum width of the configuration. - /// - /// This method is intended to be used when creating a forked - /// configuration for a particular formatting context in which the - /// total available width needs to be reduced. This reduces the - /// size of max_width, and all other properties affected by small - /// heuristics, without treating those adjustments as overrides. - /// - /// As an example use case, this method is used when formatting - /// arms within a declarative macro. - #[allow(unreachable_pub)] - pub fn reduce_max_width(&mut self, delta: usize) { - self.adjust_max_width(-(delta.min(isize::MAX as usize) as isize)); - } - - /// Increases the maximum width of the configuration. - /// - /// This method is intended to be used when creating a forked - /// configuration for a particular formatting context in which the - /// total available width needs to be increased. This increases the - /// size of max_width, and all other properties affected by small - /// heuristics, without treating those adjustments as overrides. - /// - /// As an example use case, this method is used when formatting - /// arms within a declarative macro. - #[allow(unreachable_pub)] - pub fn increase_max_width(&mut self, delta: usize) { - self.adjust_max_width(delta.min(isize::MAX as usize) as isize); - } - - /// Adjusts the maximum width of the configuration. - /// - /// This method is intended to be used when creating a forked - /// configuration for a particular formatting context in which the - /// total available width needs to be reduced. This adjusts the - /// size of max_width, and all other properties affected by small - /// heuristics, without treating those adjustments as overrides. - /// - /// As an example use case, this method is used when formatting - /// arms within a declarative macro. - fn adjust_max_width(&mut self, delta: isize) { - // NB: we need to either saturate or report an error (or some kind of testable - // warning). I picked to saturate here. - let adjust = |value: usize| value.saturating_add_signed(delta); - - self.array_width.2 = adjust(self.array_width.2); - self.attr_fn_like_width.2 = adjust(self.attr_fn_like_width.2); - self.chain_width.2 = adjust(self.chain_width.2); - self.fn_call_width.2 = adjust(self.fn_call_width.2); - self.single_line_if_else_max_width.2 = adjust(self.single_line_if_else_max_width.2); - self.single_line_let_else_max_width.2 = - adjust(self.single_line_let_else_max_width.2); - self.struct_lit_width.2 = adjust(self.struct_lit_width.2); - self.struct_variant_width.2 = adjust(self.struct_variant_width.2); - - self.max_width.2 = adjust(self.max_width.2); - self.set_heuristics(); - } - fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) { let max_width = self.max_width.2; let get_width_value = | diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs index 7ecf2ec3b58cf..0180bb89841c0 100644 --- a/src/tools/rustfmt/src/config/mod.rs +++ b/src/tools/rustfmt/src/config/mod.rs @@ -689,23 +689,6 @@ mod test { assert_eq!(config.verbose(), Verbosity::Normal); } - #[test] - fn test_adjust_max_width() { - // Regression tests for #7147, where we didn't handle overflows / integral cast outside of - // range properly. - - // Reduce with huge amount saturates to zero instead of wraparound. - let mut config = Config::default(); - config.reduce_max_width(usize::MAX); - assert_eq!(config.max_width(), 0); - - // Increase with huge amount saturates instead of wraparound. - let mut config = Config::default(); - config.set().max_width(usize::MAX - 1); - config.increase_max_width(2); - assert_eq!(config.max_width(), usize::MAX); - } - #[test] fn test_config_used_to_toml() { let config = Config::default(); diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 0b82acba264da..a9eccf1c7785a 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1371,13 +1371,31 @@ pub(crate) fn rewrite_literal( token::LitKind::Str => rewrite_string_lit(context, span, shape), token::LitKind::Integer => rewrite_int_lit(context, token_lit, span, shape), token::LitKind::Float => rewrite_float_lit(context, token_lit, span, shape), - _ => wrap_str( - context.snippet(span).to_owned(), - context.config.max_width(), - context.config.tab_spaces(), - shape, - ) - .max_width_error(shape.width, span), + token::LitKind::Bool + | token::LitKind::Byte + | token::LitKind::ByteStr + | token::LitKind::ByteStrRaw(_) + | token::LitKind::Char + | token::LitKind::CStr + | token::LitKind::CStrRaw(_) + | token::LitKind::StrRaw(_) + | token::LitKind::Err(_) => { + // token::LitKind::Bool is true or false + // token::LitKind::Byte is b'' + // token::LitKind::ByteStr is b"" + // token::LitKind::ByteStrRaw(_) is br"" or br#""# + // token::LitKind::Char is '' + // token::LitKind::CStr is c"" + // token::LitKind::CStrRaw(_) is cr"" or cr#""# + // token::LitKind::StrRaw(_) is r"" or r#""# + wrap_str( + context.snippet(span).to_owned(), + context.config.max_width(), + context.config.tab_spaces(), + shape, + ) + .max_width_error(shape.width, span) + } } } diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs index 4e82f89e437b1..d5c27400106c6 100644 --- a/src/tools/rustfmt/src/macros.rs +++ b/src/tools/rustfmt/src/macros.rs @@ -21,16 +21,19 @@ use rustc_span::{BytePos, DUMMY_SP, Ident, Pos, Span, Symbol}; use tracing::debug; use crate::comment::{ - CharClasses, FindUncommented, FullCodeCharKind, LineClasses, contains_comment, + CharClasses, FindUncommented, FullCodeCharKind, LineClasses, + combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment, }; -use crate::config::StyleEdition; use crate::config::lists::*; +use crate::config::{ControlBraceStyle, StyleEdition}; use crate::expr::{RhsAssignKind, rewrite_array, rewrite_assign_rhs}; use crate::header::{HeaderPart, format_header}; use crate::is_nightly_channel; use crate::lists::{ListFormatting, itemize_list, write_list}; use crate::overflow; -use crate::parse::macros::cfg_select::{CfgSelectFormatPredicate, parse_cfg_select_arms}; +use crate::parse::macros::cfg_select::{ + CfgSelectArm, CfgSelectFormatPredicate, parse_cfg_select_arms, +}; use crate::parse::macros::lazy_static::parse_lazy_static; use crate::parse::macros::{ParsedMacroArgs, parse_expr, parse_macro_args}; use crate::rewrite::{ @@ -40,8 +43,9 @@ use crate::shape::{Indent, Shape}; use crate::source_map::SpanUtils; use crate::spanned::Spanned; use crate::utils::{ - NodeIdExt, extra_offset, filtered_str_fits, indent_next_line, is_empty_line, mk_sp, - remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout, + NodeIdExt, extra_offset, filtered_str_fits, indent_next_line, is_empty_line, + last_line_contains_single_line_comment, mk_sp, remove_trailing_white_spaces, rewrite_ident, + trim_left_preserve_layout, }; use crate::visitor::FmtVisitor; @@ -1361,13 +1365,15 @@ impl MacroBranch { } else { shape.indent.block_indent(&config) }; - config.reduce_max_width(body_indent.width()); + let new_width = config.max_width() - body_indent.width(); + config.set().max_width(new_width); // First try to format as items, then as statements. let new_body_snippet = match crate::format_snippet(&body_str, &config, true) { Some(new_body) => new_body, None => { - config.increase_max_width(config.tab_spaces()); + let new_width = new_width + config.tab_spaces(); + config.set().max_width(new_width); match crate::format_code_block(&body_str, &config, true) { Some(new_body) => new_body, None => { @@ -1622,47 +1628,7 @@ fn format_cfg_select( "}", |arm| arm.span().lo(), |arm| arm.span().hi(), - |arm| { - let predicate_str = match &arm.predicate { - CfgSelectFormatPredicate::Wildcard(_t) => Cow::Borrowed("_"), - CfgSelectFormatPredicate::Cfg(meta_item_inner) => { - Cow::Owned(meta_item_inner.rewrite_result(context, nested_shape)?) - } - }; - - match arm.double_block_inner(context) { - // FIXME(ytmimi) The formatting for the `$predicate => {{}}` case isn't very robust. - // There's the potential that we'll lose comments in between the predicate, the `=>` - // and the body. We also don't handle comments like `{/*comment*/{}/*comment*/}`. - // The `rewrite_match_body` branch also handles `control_brace_style` better. - // That said, it helps fix . - Some(expr) => { - let trailing_comma = if arm.trailing_comma.is_some() { - "," - } else { - "" - }; - let offset = extra_offset(&predicate_str, nested_shape) + " => {".len(); - let nested_shape = nested_shape - .offset_left(offset, arm.span())? - .sub_width("}".len() + trailing_comma.len(), arm.span())?; - let body = expr - .rewrite_result(context, nested_shape) - .map(|rw| format!("{{{rw}}}"))?; - - Ok(format!("{predicate_str} => {body}{trailing_comma}")) - } - None => crate::matches::rewrite_match_body( - context, - &arm.expr, - &predicate_str, - nested_shape, - false, - arm.arrow.span, - last_arm.is_some_and(|la| la == arm), - ), - } - }, + |arm| rewrite_cfg_select_arm(context, nested_shape, last_arm, arm), // Start Span after the opening delimiter. For example, // ``` // cfg_select! { @@ -1694,3 +1660,126 @@ fn format_cfg_select( Ok(rewrite) } + +fn rewrite_cfg_select_arm( + context: &RewriteContext<'_>, + nested_shape: Shape, + last_arm: Option<&CfgSelectArm>, + arm: &CfgSelectArm, +) -> Result { + let try_rewrite = || { + let predicate_str = match &arm.predicate { + CfgSelectFormatPredicate::Wildcard(_t) => Cow::Borrowed("_"), + CfgSelectFormatPredicate::Cfg(meta_item_inner) => { + Cow::Owned(meta_item_inner.rewrite_result(context, nested_shape)?) + } + }; + + // We need to account for comments between predicate and `=>`. + let before_arrow_sp = arm.predicate.span().between(arm.arrow.span); + let before_arrow = context.snippet(before_arrow_sp); + let predicate_str = if contains_comment(before_arrow) { + // We cannot rewrite if the last line is a line comment, it will comment out + // `=>`. + if last_line_contains_single_line_comment(before_arrow.trim_end()) { + return Ok(context.snippet(arm.span()).to_owned()); + } + + Cow::Owned(combine_strs_with_missing_comments( + context, + &predicate_str, + "", + before_arrow_sp, + nested_shape, + true, + )?) + } else { + predicate_str + }; + + match arm.maybe_double_block_concise_formatting(context) { + // FIXME(ytmimi): the `rewrite_match_body` branch also handles + // `control_brace_style` better. That said, it helps fix + // . + Some(inner_expr) => { + // ``` + // => /* comment */ {{ ... }} + // ^------------- between span + // ``` + let after_arrow_comment = context + .snippet(arm.arrow.span.between(arm.expr.span())) + .trim(); + let after_arrow_comment = if after_arrow_comment.is_empty() { + None + } else { + Some(rewrite_comment( + after_arrow_comment, + false, + nested_shape, + context.config, + )?) + }; + + let trailing_comma = if arm.trailing_comma.is_some() { + "," + } else { + "" + }; + + // Force next-line layout if there's a comment after `=>`, like `match` arms. + let next_line_open_brace = matches!( + context.config.control_brace_style(), + ControlBraceStyle::AlwaysNextLine, + ) || after_arrow_comment.is_some(); + + let prefix_width = if next_line_open_brace { + 0 + } else { + extra_offset(&predicate_str, nested_shape) + " => ".len() + }; + + let body_shape = nested_shape + .offset_left(prefix_width + "{".len(), arm.span())? + .sub_width("}".len() + trailing_comma.len(), arm.span())?; + let body = inner_expr.rewrite_result(context, body_shape)?; + + let body = format!("{{{body}}}{trailing_comma}"); + match after_arrow_comment { + Some(comment) => { + let indent = nested_shape.indent.to_string_with_newline(context.config); + Ok(format!("{predicate_str} =>{indent}{comment}{indent}{body}")) + } + None if next_line_open_brace => { + let indent = nested_shape.indent.to_string_with_newline(context.config); + Ok(format!("{predicate_str} =>{indent}{body}")) + } + None => Ok(format!("{predicate_str} => {body}")), + } + } + None => { + // Note that we can't _just_ pass the `=>`'s span, we need to pass + // + // ``` + // => /* comment */ #[attr] { ... } + // ^--------------- this whole span until outer expr + // ``` + // + // Using `Spanned::span` here for `arm.expr` to account for outer + // attributes. + crate::matches::rewrite_match_body( + context, + &arm.expr, + &predicate_str, + nested_shape, + false, + arm.arrow.span.until(arm.expr.span()), + last_arm.is_some_and(|la| la == arm), + ) + } + } + }; + + let rw = try_rewrite()?; + // NB: there could be a comment between body and trailing comma. + Ok(recover_comment_removed(rw, arm.span(), context)) +} diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 495f12c8f5d5d..08accda2fbd09 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -13,9 +13,13 @@ pub(crate) fn parse_cfg_if<'a>( psess: &'a ParseSess, mac: &'a ast::MacCall, ) -> Result, &'static str> { - match catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(psess, mac))) { - Ok(Ok(items)) => Ok(items), - Ok(err @ Err(_)) => err, + let result = catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(psess, mac))); + let dcx = psess.inner().dcx(); + let recovered = dcx.has_errors().is_some(); + dcx.reset_err_count(); + match result { + Ok(Ok(_)) if recovered => Err("cfg_if! parsed with recovery"), + Ok(res) => res, Err(..) => Err("failed to parse cfg_if!"), } } diff --git a/src/tools/rustfmt/src/parse/macros/cfg_select.rs b/src/tools/rustfmt/src/parse/macros/cfg_select.rs index 5c5963320d6f7..6db647eaabb88 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_select.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_select.rs @@ -163,38 +163,57 @@ impl std::fmt::Debug for CfgSelectArm { } impl CfgSelectArm { - /// Is the cfg_select! arm written with two consecutive blocks. - /// For example `$predicate => {{}}`. If so, extract the inner block. - /// rustfmt will preserve the double block syntax. - pub(crate) fn double_block_inner(&self, context: &RewriteContext<'_>) -> Option<&ast::Expr> { - // In order to see if we can reach in and grab the inner block we'll - // check the following properties of the outer block: + /// Is the `cfg_select!` arm written with two consecutive blocks in a way that we can apply a + /// concise formatting happy path? For example: + /// + /// ```text + /// $predicate => {{}} + /// ``` + /// + /// If so, extract the inner block. rustfmt will preserve the double block syntax. + pub(crate) fn maybe_double_block_concise_formatting( + &self, + context: &RewriteContext<'_>, + ) -> Option<&ast::Expr> { + // To be able to safely use the concise double block `{{ ... }}` concise formatting, the + // outer block must satisfy all of the following properties: + // // 1. It has a single statement that's also a block // 2. It doesn't have a label // 3. It isn't an unsafe block // 4. It doesn't have any attributes - match &self.expr.kind { - ast::ExprKind::Block(b, label) - if b.stmts.len() == 1 + // 5. There are no comments between the outer blocks and the inner blocks, i.e. + // ``` + // { /* A */ { ... } /* B */ } + // ``` + let outer_expr = &self.expr; + match &outer_expr.kind { + ast::ExprKind::Block(outer_block, label) + if let [stmt] = outer_block.stmts.as_slice() && label.is_none() - && !is_unsafe_block(b) + && !is_unsafe_block(&outer_block) && self.expr.attrs.is_empty() => { - match &b.stmts[0].kind { - // This is where we check that the inner block's statement is also a block - ast::StmtKind::Expr(e) if matches!(e.kind, ast::ExprKind::Block(..)) => { - let pre_span = b.span.shrink_to_lo().between(e.span()); - let pre_snippet = context.snippet(pre_span).trim(); - - let post_span = e.span().shrink_to_hi().between(b.span.shrink_to_hi()); - let post_snippet = context.snippet(post_span).trim(); - - if !contains_comment(pre_snippet) && !contains_comment(post_snippet) { - // To prevent comment loss between the blocks we only want to return - // the inner block if there aren't any pre / post comments. - Some(e) - } else { + match &stmt.kind { + // The inner expr has to be a block. + ast::StmtKind::Expr(e) + if let ast::ExprKind::Block(ref inner_block, _inner_label) = e.kind => + { + // Check for comments in between outer/inner blocks. If there are in-between + // comments, we should not apply the concise formatting. Let's call them + // ``` + // { { ... } } + // ^--- ^--- + // pre_sp post_sp + // ``` + let pre_sp = outer_block.span.until(inner_block.span); + let post_sp = outer_block.span.with_lo(inner_block.span.hi()); + if contains_comment(context.snippet(pre_sp)) + || contains_comment(context.snippet(post_sp)) + { None + } else { + Some(e) } } _ => None, diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs index 96b96700a9288..5d5be709e5fb5 100644 --- a/src/tools/rustfmt/src/test/mod.rs +++ b/src/tools/rustfmt/src/test/mod.rs @@ -44,7 +44,7 @@ const FILE_SKIP_LIST: &[&str] = &[ "issue-3253/bar.rs", "issue-3253/paths", // This directory is directly tested by format_files_find_new_files_via_cfg_select - "cfg_select", + "cfg_select_multifile", // These files and directory are a part of modules defined inside `cfg_attr(..)`. "cfg_mod/dir", "cfg_mod/bar.rs", @@ -575,8 +575,8 @@ fn format_files_find_new_files_via_cfg_select() { // transparent mod discovery, and to ensure that it does not suffer // from a similar issue as cfg_if! support did with issue-4656. let files = vec![ - Path::new("tests/source/cfg_select/lib2.rs"), - Path::new("tests/source/cfg_select/lib.rs"), + Path::new("tests/source/cfg_select_multifile/lib2.rs"), + Path::new("tests/source/cfg_select_multifile/lib.rs"), ]; let config = Config::default(); diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 28c2740444822..6451595449046 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1015,14 +1015,6 @@ impl Rewrite for ast::Ty { }) } ast::TyKind::CVarArgs => Ok("...".to_owned()), - ast::TyKind::FieldOf(ref ty, ref variant, ref field) => { - let ty = ty.rewrite_result(context, shape)?; - if let Some(variant) = variant { - Ok(format!("builtin # field_of({ty}, {variant}.{field})")) - } else { - Ok(format!("builtin # field_of({ty}, {field})")) - } - } ast::TyKind::UnsafeBinder(ref binder) => { let mut result = String::new(); if binder.generic_params.is_empty() { @@ -1049,7 +1041,10 @@ impl Rewrite for ast::Ty { result.push_str(&rewrite); Ok(result) } - ast::TyKind::Pat(..) | ast::TyKind::View(..) | ast::TyKind::GcaMacro(..) => { + ast::TyKind::FieldOf(..) + | ast::TyKind::GcaMacro(..) + | ast::TyKind::Pat(..) + | ast::TyKind::View(..) => { // These don't normally occur in the AST because macros aren't expanded. However, // rustfmt tries to parse macro arguments when formatting macros, so it's not // totally impossible for rustfmt to come across these nodes when formatting a file. diff --git a/src/tools/rustfmt/tests/config/issue_4660/Cargo.toml b/src/tools/rustfmt/tests/config/issue_4660/Cargo.toml index c716e9d057548..c9ddf1793b88f 100644 --- a/src/tools/rustfmt/tests/config/issue_4660/Cargo.toml +++ b/src/tools/rustfmt/tests/config/issue_4660/Cargo.toml @@ -1,2 +1,6 @@ -[workspace] -members = ["inner_lib"] +[package] +name = "inner_lib" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/tools/rustfmt/tests/config/issue_4660/configs/rustfmt.hard_tabs.toml b/src/tools/rustfmt/tests/config/issue_4660/configs/rustfmt.hard_tabs.toml new file mode 100644 index 0000000000000..218e203215e94 --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue_4660/configs/rustfmt.hard_tabs.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/src/tools/rustfmt/tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml b/src/tools/rustfmt/tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml deleted file mode 100644 index c7ad93bafe36c..0000000000000 --- a/src/tools/rustfmt/tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml +++ /dev/null @@ -1 +0,0 @@ -disable_all_formatting = true diff --git a/src/tools/rustfmt/tests/config/issue_4660/inner_bin/Cargo.toml b/src/tools/rustfmt/tests/config/issue_4660/inner_bin/Cargo.toml deleted file mode 100644 index bb6a80cd0ce9b..0000000000000 --- a/src/tools/rustfmt/tests/config/issue_4660/inner_bin/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "inner_bin" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/src/tools/rustfmt/tests/config/issue_4660/inner_bin/src/main.rs b/src/tools/rustfmt/tests/config/issue_4660/inner_bin/src/main.rs deleted file mode 100644 index 21c34773b8af5..0000000000000 --- a/src/tools/rustfmt/tests/config/issue_4660/inner_bin/src/main.rs +++ /dev/null @@ -1 +0,0 @@ -fn main(){println!("Hello, world!")} diff --git a/src/tools/rustfmt/tests/config/issue_4660/inner_lib/Cargo.toml b/src/tools/rustfmt/tests/config/issue_4660/inner_lib/Cargo.toml deleted file mode 100644 index c9ddf1793b88f..0000000000000 --- a/src/tools/rustfmt/tests/config/issue_4660/inner_lib/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "inner_lib" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/src/tools/rustfmt/tests/config/issue_4660/inner_lib/rustfmt.toml b/src/tools/rustfmt/tests/config/issue_4660/inner_lib/rustfmt.toml deleted file mode 100644 index c7ad93bafe36c..0000000000000 --- a/src/tools/rustfmt/tests/config/issue_4660/inner_lib/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -disable_all_formatting = true diff --git a/src/tools/rustfmt/tests/config/issue_4660/inner_lib/src/lib.rs b/src/tools/rustfmt/tests/config/issue_4660/inner_lib/src/lib.rs deleted file mode 100644 index 42375c99d2c97..0000000000000 --- a/src/tools/rustfmt/tests/config/issue_4660/inner_lib/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub fn add(left:u64,right:u64)->u64{left+right} diff --git a/src/tools/rustfmt/tests/config/issue_4660/rustfmt.toml b/src/tools/rustfmt/tests/config/issue_4660/rustfmt.toml new file mode 100644 index 0000000000000..8a1751f67698f --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue_4660/rustfmt.toml @@ -0,0 +1 @@ +use_field_init_shorthand = true diff --git a/src/tools/rustfmt/tests/config/issue_4660/src/lib.rs b/src/tools/rustfmt/tests/config/issue_4660/src/lib.rs new file mode 100644 index 0000000000000..012fb0f850f8c --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue_4660/src/lib.rs @@ -0,0 +1,2 @@ +mod longhand_field_init; +mod with_spaces; diff --git a/src/tools/rustfmt/tests/config/issue_4660/src/longhand_field_init.rs b/src/tools/rustfmt/tests/config/issue_4660/src/longhand_field_init.rs new file mode 100644 index 0000000000000..87ee30033c955 --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue_4660/src/longhand_field_init.rs @@ -0,0 +1,10 @@ +struct Foo { + x: u32, + y: u32, +} +fn foo() -> Foo { + let x = 1; + let y = 2; + + Foo { x: x, y: y } +} diff --git a/src/tools/rustfmt/tests/config/issue_4660/src/with_spaces.rs b/src/tools/rustfmt/tests/config/issue_4660/src/with_spaces.rs new file mode 100644 index 0000000000000..211d2de3c959e --- /dev/null +++ b/src/tools/rustfmt/tests/config/issue_4660/src/with_spaces.rs @@ -0,0 +1,3 @@ +fn f() { + // comment +} diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs index 5fbf64d8862c1..04ef79db920e3 100644 --- a/src/tools/rustfmt/tests/rustfmt/main.rs +++ b/src/tools/rustfmt/tests/rustfmt/main.rs @@ -1,13 +1,12 @@ //! Integration tests for rustfmt. -use indoc::panicdoc; use std::env; -use std::fs::{File, remove_file}; +use std::fs::File; use std::io::Write; use std::path::Path; use std::process::{Command, Stdio}; -use rustfmt_config_proc_macro::{nightly_only_test, rustfmt_only_ci_test, stable_only_test}; +use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test, rustfmt_only_ci_test}; /// Run the rustfmt executable with environment vars set and return its output. /// If `input` is given, it is piped to the executable's stdin. @@ -16,7 +15,7 @@ fn rustfmt_with_extra( working_dir: Option<&str>, envs: &[(&str, &str)], input: Option<&str>, -) -> (String, String) { +) -> (String, String, i32) { let rustfmt_exe = env!("CARGO_BIN_EXE_rustfmt"); let bin_dir = Path::new(rustfmt_exe).parent().unwrap(); @@ -48,96 +47,142 @@ fn rustfmt_with_extra( Ok(output) => ( String::from_utf8(output.stdout).expect("utf-8"), String::from_utf8(output.stderr).expect("utf-8"), + output.status.code().expect("should exit with a status"), ), Err(e) => panic!("failed to run `{cmd:?} {args:?}`: {e}"), } } -fn rustfmt(args: &[&str]) -> (String, String) { +fn rustfmt(args: &[&str]) -> (String, String, i32) { rustfmt_with_extra(args, None, &[], None) } -macro_rules! assert_that { - ($args:expr, $($check:ident $check_args:tt)&&+) => { - let (stdout, stderr) = rustfmt($args); - if $(!stdout.$check$check_args && !stderr.$check$check_args)||* { - let args = $args; - let expected = stringify!($( $check$check_args )&&*); - panicdoc! {" - Output not expected for rustfmt {args:?} - expected: {expected} - actual stdout: - {stdout} - actual stderr: - {stderr}", - }; - } - }; +#[test] +fn print_config_errors_on_unknown_option() { + let args = &["--print-config", "unknown"]; + + let (stdout, stderr, exit_code) = rustfmt(args); + + assert_eq!(&stdout, ""); + assert!( + stderr.contains("Unknown print-config option"), + "expected helpful error message, got: {stderr}" + ); + assert_eq!(exit_code, 1); } -#[rustfmt_only_ci_test] #[test] -fn print_config() { - assert_that!( - &["--print-config", "unknown"], - starts_with("Unknown print-config option") +fn print_config_default() { + let args = &["--print-config", "default"]; + let (stdout, stderr, exit_code) = rustfmt(args); + + assert!( + stdout.contains("max_width = 100"), + "expected stdout to contain a default config, got: {stdout}", ); - assert_that!(&["--print-config", "default"], contains("max_width = 100")); - assert_that!(&["--print-config", "minimal"], contains("PATH required")); - assert_that!( - &["--print-config", "minimal", "minimal-config"], - contains("doesn't work with standard input.") + assert_eq!(&stderr, ""); + assert_eq!(exit_code, 0) +} + +#[test] +fn print_config_errors_minimal_with_no_path() { + let args = &["--print-config", "minimal"]; + + let (stdout, stderr, exit_code) = rustfmt(args); + + assert_eq!(stdout, ""); + assert_eq!( + stderr, "The `--print-config=minimal` option requires an output path to write to\n", + "expected helpful error message, got: {stderr}" ); + assert_eq!(exit_code, 1) +} - let (stdout, stderr) = rustfmt(&[ +#[test] +fn print_config_errors_minimal_without_input_file() { + let args = &["--print-config", "minimal", "minimal.toml"]; + + let (stdout, stderr, exit_code) = rustfmt(args); + + assert_eq!(&stdout, ""); + assert_eq!( + stderr, "The `--print-config=minimal` option doesn't work with standard input.\n", + "expected helpful error message, got: {stderr}" + ); + assert_eq!(exit_code, 1); +} + +#[rustfmt_only_ci_test] +#[test] +fn print_config_writes_to_file() { + let out_file = tempfile::tempdir().unwrap().keep().join("minimal.toml"); + + let args = &[ + "--config-path", + Path::new("tests/config/disable_all_formatting.toml") + .to_str() + .unwrap(), "--print-config", "minimal", - "minimal-config", + out_file.to_str().unwrap(), "src/shape.rs", - ]); + ]; + + let (stdout, stderr, exit_code) = rustfmt(args); + + assert_eq!(stderr, ""); + assert!(out_file.exists(), "stdout:\n{stdout}\nstderr:\n{stderr}"); + assert_eq!(exit_code, 0); +} + +#[test] +fn print_config_merges_override_from_args() { + let args = &[ + "--print-config", + "current", + ".", + "--config=color=Never,edition=2018", + ]; + + let (stdout, stderr, exit_code) = rustfmt(args); + + assert_eq!(stderr, ""); assert!( - Path::new("minimal-config").exists(), - "stdout:\n{stdout}\nstderr:\n{stderr}" + stdout.contains(r#"color = "Never""#) && stdout.contains(r#"edition = "2018""#), + "expected overrides in stdout, got: {stdout}", ); - remove_file("minimal-config").unwrap(); + assert_eq!(exit_code, 0); } -#[rustfmt_only_ci_test] #[test] -fn inline_config() { - // single invocation - assert_that!( - &[ - "--print-config", - "current", - ".", - "--config=color=Never,edition=2018" - ], - contains("color = \"Never\"") && contains("edition = \"2018\"") - ); +fn print_config_merges_multiple_overrides_from_args() { + let args = &[ + "--print-config", + "current", + ".", + "--config", + "color=never,edition=2018", + "--config", + "color=always,format_strings=true", + ]; + + let (stdout, stderr, exit_code) = rustfmt(args); - // multiple overriding invocations - assert_that!( - &[ - "--print-config", - "current", - ".", - "--config", - "color=never,edition=2018", - "--config", - "color=always,format_strings=true" - ], - contains("color = \"Always\"") - && contains("edition = \"2018\"") - && contains("format_strings = true") + assert_eq!(stderr, ""); + assert!( + stdout.contains(r#"color = "Always""#) + && stdout.contains(r#"edition = "2018""#) + && stdout.contains("format_strings = true"), + "expected overrides in stdout, got: {stdout}", ); + assert_eq!(exit_code, 0); } #[stable_only_test] #[test] fn rustfmt_usage_text() { let args = ["--help"]; - let (stdout, _) = rustfmt(&args); + let (stdout, _, exit_code) = rustfmt(&args); insta::assert_snapshot!(stdout, @" Format Rust code @@ -179,13 +224,14 @@ fn rustfmt_usage_text() { -h, --help [=TOPIC] Show this message or help about a specific topic: `config` "); + assert_eq!(exit_code, 0); } #[nightly_only_test] #[test] fn rustfmt_nightly_usage_text() { let args = ["--help"]; - let (stdout, _) = rustfmt(&args); + let (stdout, _, exit_code) = rustfmt(&args); insta::assert_snapshot!(stdout, @" Format Rust code @@ -239,6 +285,7 @@ fn rustfmt_nightly_usage_text() { -h, --help [=TOPIC] Show this message or help about a specific topic: `config` or `file-lines` "); + assert_eq!(exit_code, 0); } #[test] @@ -253,36 +300,44 @@ fn mod_resolution_error_multiple_candidate_files() { ); let args = ["tests/mod-resolver/issue-5167/src/lib.rs"]; - let (_stdout, stderr) = rustfmt(&args); - assert!(stderr.contains(&error_message)) + let (_stdout, stderr, exit_code) = rustfmt(&args); + + assert!(stderr.contains(&error_message)); + assert_eq!(exit_code, 1); } #[test] fn mod_resolution_error_sibling_module_not_found() { let args = ["tests/mod-resolver/module-not-found/sibling_module/lib.rs"]; - let (_stdout, stderr) = rustfmt(&args); + let (_stdout, stderr, exit_code) = rustfmt(&args); + // Module resolution fails because we're unable to find `a.rs` in the same directory as lib.rs - assert!(stderr.contains("a.rs does not exist")) + assert!(stderr.contains("a.rs does not exist")); + assert_eq!(exit_code, 1); } #[test] fn mod_resolution_error_relative_module_not_found() { let args = ["tests/mod-resolver/module-not-found/relative_module/lib.rs"]; - let (_stdout, stderr) = rustfmt(&args); + let (_stdout, stderr, exit_code) = rustfmt(&args); + // The file `./a.rs` and directory `./a` both exist. // Module resolution fails because we're unable to find `./a/b.rs` #[cfg(not(windows))] assert!(stderr.contains("a/b.rs does not exist")); #[cfg(windows)] assert!(stderr.contains("a\\b.rs does not exist")); + assert_eq!(exit_code, 1); } #[test] fn mod_resolution_error_path_attribute_does_not_exist() { let args = ["tests/mod-resolver/module-not-found/bad_path_attribute/lib.rs"]; - let (_stdout, stderr) = rustfmt(&args); + let (_stdout, stderr, exit_code) = rustfmt(&args); + // The path attribute points to a file that does not exist assert!(stderr.contains("does_not_exist.rs does not exist")); + assert_eq!(exit_code, 1); } #[test] @@ -294,10 +349,11 @@ fn rustfmt_emits_error_on_line_overflow_true() { "tests/cargo-fmt/source/issue_3164/src/main.rs", ]; - let (_stdout, stderr) = rustfmt(&args); + let (_stdout, stderr, exit_code) = rustfmt(&args); assert!(stderr.contains( "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" - )) + )); + assert_eq!(exit_code, 1); } #[test] @@ -315,8 +371,11 @@ fn dont_emit_ICE() { let panic_re = regex::Regex::new("thread.*panicked").unwrap(); for file in files { let args = [file]; - let (_stdout, stderr) = rustfmt(&args); + + let (_stdout, stderr, exit_code) = rustfmt(&args); + assert!(!panic_re.is_match(&stderr)); + assert_eq!(exit_code, 0); } } @@ -332,8 +391,10 @@ fn rustfmt_emits_error_when_control_brace_style_is_always_next_line() { "tests/target/issue_5912.rs", ]; - let (_stdout, stderr) = rustfmt(&args); - assert!(!stderr.contains("error[internal]: left behind trailing whitespace")) + let (_stdout, stderr, exit_code) = rustfmt(&args); + + assert!(!stderr.contains("error[internal]: left behind trailing whitespace")); + assert_eq!(exit_code, 0); } #[nightly_only_test] @@ -343,9 +404,11 @@ fn rustfmt_generates_no_error_if_failed_format_code_in_doc_comments() { let file = "tests/target/issue-6109.rs"; let args = ["--config", "format_code_in_doc_comments=true", file]; - let (stdout, stderr) = rustfmt(&args); + let (stdout, stderr, exit_code) = rustfmt(&args); + assert!(stderr.is_empty()); assert!(stdout.is_empty()); + assert_eq!(exit_code, 0); } #[test] @@ -353,43 +416,123 @@ fn rustfmt_error_improvement_regarding_invalid_toml() { // See also https://github.com/rust-lang/rustfmt/issues/6302 let invalid_toml_config = "tests/config/issue-6302.toml"; let args = ["--config-path", invalid_toml_config]; - let (_stdout, stderr) = rustfmt(&args); + let (_stdout, stderr, exit_code) = rustfmt(&args); let toml_path = Path::new(invalid_toml_config).canonicalize().unwrap(); let expected_error_message = format!("The file `{}` failed to parse", toml_path.display()); assert!(stderr.contains(&expected_error_message)); + assert_eq!(exit_code, 1); } #[test] fn config_path_walks_parent_directories_with_dir_name() { - let src_dir = "tests/config/issue_4660/inner_lib/src"; - let src_file = src_dir.to_owned() + "/lib.rs"; - let args = ["--config-path", src_dir, "--check", &src_file]; - let (stdout, stderr) = rustfmt(&args); + let src_dir = Path::new("tests/config/issue_4660/src"); + let src_file = src_dir.join("longhand_field_init.rs"); + let args = [ + "--config-path", + &src_dir.to_str().unwrap(), + "--check", + "--files-with-diff", + &src_file.to_str().unwrap(), + ]; + + let (stdout, stderr, exit_code) = rustfmt(&args); assert_eq!(stderr, ""); - // Due to `disable_all_formatting = true` in `tests/config/issue_4660/inner_lib/rustfmt.toml`, - // the source file should not be modified. - assert_eq!(stdout, ""); + assert_eq!( + stdout, + format!("{}\n", src_file.canonicalize().unwrap().display()), + // this config sets `use_field_init_shorthand = true` + "we should walk up to tests/config/issue_4660/rustfmt.toml" + ); + assert_eq!(exit_code, 1); } +// on unix [`std::env::home_dir`] reads the `HOME` env var. +#[cfg(unix)] #[test] -fn config_path_does_not_walk_parent_directories_with_toml_name() { - let src_dir = "tests/config/issue_4660/inner_bin/src"; - let toml_file = src_dir.to_owned() + "/.rustfmt.unstable.toml"; - let src_file = src_dir.to_owned() + "/main.rs"; - let args = ["--config-path", &toml_file, "--check", &src_file]; - let (stdout, stderr) = rustfmt(&args); +fn config_path_searches_home_dir_when_dir_path_no_resolve() { + // move the src file to a tempdir, since we'll search up from there looking for the config file + // so we need to avoid using a path within this repo + let new_src_dir = tempfile::tempdir().unwrap().keep(); + let src_file = Path::new("tests/config/issue_4660/src/with_spaces.rs"); + let new_src_path = new_src_dir.join("with_spaces.rs"); + let config_file = Path::new("tests/config/issue_4660/configs/rustfmt.hard_tabs.toml"); + let homedir_path = tempfile::tempdir().unwrap().keep(); + + std::fs::copy(&config_file, homedir_path.join("rustfmt.toml")).unwrap(); + std::fs::copy(&src_file, &new_src_path).unwrap(); + + let args = [ + "--check", + "--files-with-diff", + &new_src_path.to_str().unwrap(), + ]; + let env = &[("HOME", homedir_path.to_str().unwrap())]; + + let (stdout, stderr, exit_code) = rustfmt_with_extra(&args, None, env, None); + + assert_eq!(stderr, ""); + assert_eq!( + stdout, + format!("{}\n", new_src_path.canonicalize().unwrap().display()), + "should search in HOME" + ); + assert_eq!(exit_code, 1); +} + +// The behaviour [`dirs::config_dir`] is os-dependent, so pick one and test to that. +#[cfg(target_os = "linux")] +#[test] +fn config_path_searches_config_dir_when_dir_path_no_resolve() { + // move the src file to a tempdir, since we'll search up from there looking for the config file + let new_src_dir = tempfile::tempdir().unwrap().keep(); + let src_file = Path::new("tests/config/issue_4660/src/with_spaces.rs"); + let new_src_path = new_src_dir.join("with_spaces.rs"); + let config_file = Path::new("tests/config/issue_4660/configs/rustfmt.hard_tabs.toml"); + let xdg_config_dir_path = tempfile::tempdir().unwrap().keep(); + let config_path = xdg_config_dir_path.join("rustfmt/rustfmt.toml"); + + std::fs::create_dir(&config_path.parent().unwrap()).unwrap(); + std::fs::copy(&config_file, config_path).unwrap(); + std::fs::copy(&src_file, &new_src_path).unwrap(); + + let args = [ + "--check", + "--files-with-diff", + &new_src_path.to_str().unwrap(), + ]; + let env = &[("XDG_CONFIG_HOME", xdg_config_dir_path.to_str().unwrap())]; + + let (stdout, stderr, exit_code) = rustfmt_with_extra(&args, None, env, None); + + assert_eq!(stderr, ""); + assert_eq!( + stdout, + format!("{}\n", new_src_path.canonicalize().unwrap().display()), + "should search in XDG_CONFIG_HOME" + ); + assert_eq!(exit_code, 1); +} + +#[test] +fn config_path_errors_when_invalid_file_given() { + let src_file = "not_a_file.rs"; + let config_file = "also_not_a_file.toml"; + let args = ["--config-path", &config_file, "--check", &src_file]; + + let (stdout, stderr, exit_code) = rustfmt(&args); assert_eq!( stderr, format!( "Error: unable to find a config file for the given path: `{}`\n", - Path::new(&toml_file).display(), + Path::new(&config_file).display(), ) ); assert_eq!(stdout, ""); + assert_eq!(exit_code, 1); } #[test] @@ -416,11 +559,12 @@ fn rustfmt_allow_not_a_dir_errors() { let args = [empty_rs.to_str().unwrap()]; let envs = &[("HOME", fake_home_str)]; - let (stdout, stderr) = rustfmt_with_extra(&args, Some(fake_home_str), envs, None); + let (stdout, stderr, exit_code) = rustfmt_with_extra(&args, Some(fake_home_str), envs, None); // Should pass without any errors assert_eq!(stdout, ""); assert_eq!(stderr, ""); + assert_eq!(exit_code, 0); } // FIXME(cfg_select): ungate when `cfg_select!` formatting can be enabled on stable. @@ -430,8 +574,11 @@ fn cfg_select_parser_recovery_ice_7087() { // See also https://github.com/rust-lang/rustfmt/issues/7087 let source = "cfg_select! { true => { fn foo {} } }\n"; let panic_re = regex::Regex::new("thread.*panicked").unwrap(); - let (stdout, stderr) = rustfmt_with_extra(&[], None, &[], Some(source)); + + let (stdout, stderr, exit_code) = rustfmt_with_extra(&[], None, &[], Some(source)); + assert!(!panic_re.is_match(&stderr)); // Invalid arm should cause `cfg_select!` to be re-emitted unmodified. assert_eq!(source, stdout); + assert_eq!(exit_code, 0); } diff --git a/src/tools/rustfmt/tests/source/cfg-if-error-count-leak.rs b/src/tools/rustfmt/tests/source/cfg-if-error-count-leak.rs new file mode 100644 index 0000000000000..d5e289ec95b12 --- /dev/null +++ b/src/tools/rustfmt/tests/source/cfg-if-error-count-leak.rs @@ -0,0 +1,12 @@ +//@ rustfmt-show_parse_errors: false + +cfg_if::cfg_if! { + if #[cfg(unix)] { + fn foo {} + } +} + +fn main() { + foo!(1 + 2); + foo!(1 + 2); +} diff --git a/src/tools/rustfmt/tests/source/cfg_select.rs b/src/tools/rustfmt/tests/source/cfg_select/cfg_select.rs similarity index 98% rename from src/tools/rustfmt/tests/source/cfg_select.rs rename to src/tools/rustfmt/tests/source/cfg_select/cfg_select.rs index ca6abc8aa4af2..d6dc391dd564f 100644 --- a/src/tools/rustfmt/tests/source/cfg_select.rs +++ b/src/tools/rustfmt/tests/source/cfg_select/cfg_select.rs @@ -327,7 +327,7 @@ cfg_select! { any(true, /* comment */ true, true, // true, true, ) - // comment before arrow + /* comment before arrow */ => {} not(false // comment @@ -339,12 +339,12 @@ cfg_select! { ) => "any" } -// comments before and after the `=>` get dropped right now +// comments before and after the `=>` are kept cfg_select! { any(true, true, true, true, ) - // commetn before arrow + /* comment before arrow */ => {} not(false @@ -357,6 +357,15 @@ cfg_select! { "any" } +// FIXME: not formatted, a line comment before `=>` would comment out the `=>` +cfg_select! { + any(true, + true, true, + true, ) + // line comment before arrow + => {} +} + // A bunch of mixed predicates cfg_select! { @@ -752,7 +761,7 @@ cfg_select! { any(true, /* comment */ true, true, // true, true, ) - // comment before arrow + /* comment before arrow */ => {} not(false // comment @@ -764,12 +773,12 @@ cfg_select! { ) => "any" } -// comments before and after the `=>` get dropped right now +// comments before and after the `=>` are kept cfg_select! { any(true, true, true, true, ) - // commetn before arrow + /* comment before arrow */ => {} not(false diff --git a/src/tools/rustfmt/tests/source/cfg_select_edge_cases.rs b/src/tools/rustfmt/tests/source/cfg_select/cfg_select_edge_cases.rs similarity index 82% rename from src/tools/rustfmt/tests/source/cfg_select_edge_cases.rs rename to src/tools/rustfmt/tests/source/cfg_select/cfg_select_edge_cases.rs index 3c591d3afd5a3..8bf6a3240a945 100644 --- a/src/tools/rustfmt/tests/source/cfg_select_edge_cases.rs +++ b/src/tools/rustfmt/tests/source/cfg_select/cfg_select_edge_cases.rs @@ -79,6 +79,77 @@ fn cfg_select_comments_that_might_get_lost() { // No trailing comma in source three_blocks_exclamation_point => {{/* a */{ b; c } /* d */}} } + + cfg_select! { + _ => { { x } /* after */ } + } + + cfg_select! { + _ => { { x } // after newline + } + } + + cfg_select! { + _ => /* between */ {{ x }} + } + + cfg_select! { + _ => // between trailing + {{ x }} + } + + // Trailing comma + cfg_select! { + _ => /* between */ {{ x }}, + } + cfg_select! { + _ => /* between */ {{ a; b }}, + } + + cfg_select! { + _ => /* between */ {{ a; b }} + } + + cfg_select! { + _ => /* multi + line */ {{ x }} + } + + // Comments before `=>` + cfg_select! { + _ /* before arrow */ => {{ x }} + _ /* before arrow */ => x, + _ /* before arrow */ => /* after arrow */ {{ x }} + all(target_os = "linux", target_arch = "x86_64", target_env = "gnu") /* long comment before arrow */ => {{ x }} + _ /* before arrow */ => {} + } + + cfg_select! { + // Not formatted: a line comment before `=>`. + c // before arrow + => x, + } + + cfg_select! { + _ => x /* before comma */, + } + + cfg_select! { + _ => {{ x }} /* before comma */, + } + + cfg_select! { + a => b, + } + + cfg_select! { + _ => xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx /* too long */, + } + + cfg_select! { + _ => x // trailing newline + , + } } fn other_cfg_select_cases() { @@ -203,6 +274,23 @@ fn other_cfg_select_cases() { #[inline] || { }} }; + + cfg_select! { + _ => /* before attr */ #[attr] { z } + } + + cfg_select! { + _ => #[attr] /* after attr */ { z } + } + + cfg_select! { + _ => // line comment before attr + #[attr] { z } + } + + cfg_select! { + _ => /* before attr */ #[attr] /* after attr */ { z } + } } fn long_predicate() { diff --git a/src/tools/rustfmt/tests/source/cfg_select_stable.rs b/src/tools/rustfmt/tests/source/cfg_select/cfg_select_stable.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select_stable.rs rename to src/tools/rustfmt/tests/source/cfg_select/cfg_select_stable.rs diff --git a/src/tools/rustfmt/tests/source/cfg-select-valid-then-invalid-item-error-count-leak.rs b/src/tools/rustfmt/tests/source/cfg_select/cfg_select_valid_then_invalid_item_error_count_leak.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg-select-valid-then-invalid-item-error-count-leak.rs rename to src/tools/rustfmt/tests/source/cfg_select/cfg_select_valid_then_invalid_item_error_count_leak.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/control_brace_style_always_next_line.rs b/src/tools/rustfmt/tests/source/cfg_select/control_brace_style_always_next_line.rs new file mode 100644 index 0000000000000..a12391c20298d --- /dev/null +++ b/src/tools/rustfmt/tests/source/cfg_select/control_brace_style_always_next_line.rs @@ -0,0 +1,100 @@ +//@ rustfmt-unstable: true +//@ rustfmt-edition: 2024 +//@ rustfmt-control_brace_style: AlwaysNextLine + +cfg_select! { + _ => { x } +} + +cfg_select! { + _ => { + x + } +} + +cfg_select! { + _ => {{ x }} +} + +cfg_select! { + _ => {{ + x + }} +} + +cfg_select! { + _ => unsafe { x } +} + +cfg_select! { + _ => { + unsafe { x } + } +} + +cfg_select! { + _ => // line comment + {{ x }} +} + +cfg_select! { + _ => // line comment + { a; b } +} + +cfg_select! { + _ => /* after */ {{ x }} +} + +cfg_select! { + _ => /* after */ {a; b} +} + +cfg_select! { + _ => /* after + multiline */ {{ x }} +} + +cfg_select! { + _ => /* after + multiline */ { a; b } +} + +cfg_select! { + _ => /* after */ {{ + x + }} +} + +cfg_select! { + _ => /* after */ { + a; b + } +} + +cfg_select! { + _ /* this comment is _very_ long but brace should fit ---------------------------------- */ => { a; b } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => { a; b } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => { a; b } +} + +cfg_select! { + _ /* this comment is _very_ long but shouldn't change next next line --------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => + {{ ThisLineIsShort }} +} diff --git a/src/tools/rustfmt/tests/source/cfg_select/control_brace_style_always_same_line.rs b/src/tools/rustfmt/tests/source/cfg_select/control_brace_style_always_same_line.rs new file mode 100644 index 0000000000000..cda500f61afe6 --- /dev/null +++ b/src/tools/rustfmt/tests/source/cfg_select/control_brace_style_always_same_line.rs @@ -0,0 +1,100 @@ +//@ rustfmt-unstable: true +//@ rustfmt-control_brace_style: AlwaysSameLine +// ^ NB: default value + +cfg_select! { + _ => { x } +} + +cfg_select! { + _ => { + x + } +} + +cfg_select! { + _ => {{ x }} +} + +cfg_select! { + _ => {{ + x + }} +} + +cfg_select! { + _ => unsafe { x } +} + +cfg_select! { + _ => { + unsafe { x } + } +} + +cfg_select! { + _ => // line comment + {{ x }} +} + +cfg_select! { + _ => // line comment + { a; b } +} + +cfg_select! { + _ => /* after */ {{ x }} +} + +cfg_select! { + _ => /* after */ {a; b} +} + +cfg_select! { + _ => /* after + multiline */ {{ x }} +} + +cfg_select! { + _ => /* after + multiline */ { a; b } +} + +cfg_select! { + _ => /* after */ {{ + x + }} +} + +cfg_select! { + _ => /* after */ { + a; b + } +} + +cfg_select! { + _ /* this comment is _very_ long but brace should fit ---------------------------------- */ => { a; b } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => { a; b } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => { a; b } +} + +cfg_select! { + _ /* this comment is _very_ long but shouldn't change next next line --------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => + {{ ThisLineIsShort }} +} diff --git a/src/tools/rustfmt/tests/source/issue_7045.rs b/src/tools/rustfmt/tests/source/cfg_select/issue_7045.rs similarity index 100% rename from src/tools/rustfmt/tests/source/issue_7045.rs rename to src/tools/rustfmt/tests/source/cfg_select/issue_7045.rs diff --git a/src/tools/rustfmt/tests/source/issue_7088_stable.rs b/src/tools/rustfmt/tests/source/cfg_select/issue_7088_stable.rs similarity index 100% rename from src/tools/rustfmt/tests/source/issue_7088_stable.rs rename to src/tools/rustfmt/tests/source/cfg_select/issue_7088_stable.rs diff --git a/src/tools/rustfmt/tests/source/issue_7088_unstable.rs b/src/tools/rustfmt/tests/source/cfg_select/issue_7088_unstable.rs similarity index 100% rename from src/tools/rustfmt/tests/source/issue_7088_unstable.rs rename to src/tools/rustfmt/tests/source/cfg_select/issue_7088_unstable.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/issue_7209.rs b/src/tools/rustfmt/tests/source/cfg_select/issue_7209.rs new file mode 100644 index 0000000000000..4c06baa145027 --- /dev/null +++ b/src/tools/rustfmt/tests/source/cfg_select/issue_7209.rs @@ -0,0 +1,11 @@ +//@ rustfmt-unstable: true +//@ rustfmt-edition: 2024 + +fn gettid() -> u64 { + cfg_select! { + any(target_os = "solaris", target_os = "illumos") => { + // On Solaris and Illumos, the `pthread_t` is the OS TID. + unsafe { libc::pthread_self() as u64 } + } + } +} diff --git a/src/tools/rustfmt/tests/source/cfg_select/format_me_please_1.rs b/src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_1.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select/format_me_please_1.rs rename to src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_1.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/format_me_please_2.rs b/src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_2.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select/format_me_please_2.rs rename to src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_2.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/format_me_please_3.rs b/src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_3.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select/format_me_please_3.rs rename to src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_3.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/format_me_please_4.rs b/src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_4.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select/format_me_please_4.rs rename to src/tools/rustfmt/tests/source/cfg_select_multifile/format_me_please_4.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/lib.rs b/src/tools/rustfmt/tests/source/cfg_select_multifile/lib.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select/lib.rs rename to src/tools/rustfmt/tests/source/cfg_select_multifile/lib.rs diff --git a/src/tools/rustfmt/tests/source/cfg_select/lib2.rs b/src/tools/rustfmt/tests/source/cfg_select_multifile/lib2.rs similarity index 100% rename from src/tools/rustfmt/tests/source/cfg_select/lib2.rs rename to src/tools/rustfmt/tests/source/cfg_select_multifile/lib2.rs diff --git a/src/tools/rustfmt/tests/target/cfg-if-error-count-leak.rs b/src/tools/rustfmt/tests/target/cfg-if-error-count-leak.rs new file mode 100644 index 0000000000000..48ef7ddc3ba7a --- /dev/null +++ b/src/tools/rustfmt/tests/target/cfg-if-error-count-leak.rs @@ -0,0 +1,12 @@ +//@ rustfmt-show_parse_errors: false + +cfg_if::cfg_if! { + if #[cfg(unix)] { + fn foo {} + } +} + +fn main() { + foo!(1 + 2); + foo!(1 + 2); +} diff --git a/src/tools/rustfmt/tests/target/cfg_select.rs b/src/tools/rustfmt/tests/target/cfg_select/cfg_select.rs similarity index 96% rename from src/tools/rustfmt/tests/target/cfg_select.rs rename to src/tools/rustfmt/tests/target/cfg_select/cfg_select.rs index 1c2a1ed91a7e0..9d9bbfe0b4c9a 100644 --- a/src/tools/rustfmt/tests/target/cfg_select.rs +++ b/src/tools/rustfmt/tests/target/cfg_select/cfg_select.rs @@ -277,7 +277,8 @@ cfg_select! { true, /* comment */ true, true, // true, true, - ) => {} + ) + /* comment before arrow */ => {} not( false // comment @@ -288,13 +289,29 @@ cfg_select! { ) => "any", } -// comments before and after the `=>` get dropped right now +// comments before and after the `=>` are kept cfg_select! { - any(true, true, true, true,) => {} + any(true, true, true, true,) + /* comment before arrow */ => {} - not(false) => {} + not(false) => + /* comment before opening brace */ + {} - any(false) => "any", + any(false) => + // comment before brace + { + "any" + } +} + +// FIXME: not formatted, a line comment before `=>` would comment out the `=>` +cfg_select! { + any(true, + true, true, + true, ) + // line comment before arrow + => {} } // A bunch of mixed predicates @@ -689,7 +706,8 @@ mod nested { true, /* comment */ true, true, // true, true, - ) => {} + ) + /* comment before arrow */ => {} not( false // comment @@ -700,13 +718,20 @@ mod nested { ) => "any", } - // comments before and after the `=>` get dropped right now + // comments before and after the `=>` are kept cfg_select! { - any(true, true, true, true,) => {} + any(true, true, true, true,) + /* comment before arrow */ => {} - not(false) => {} + not(false) => + /* comment before opening brace */ + {} - any(false) => "any", + any(false) => + // comment before brace + { + "any" + } } // A bunch of mixed predicates diff --git a/src/tools/rustfmt/tests/target/cfg_select_edge_cases.rs b/src/tools/rustfmt/tests/target/cfg_select/cfg_select_edge_cases.rs similarity index 80% rename from src/tools/rustfmt/tests/target/cfg_select_edge_cases.rs rename to src/tools/rustfmt/tests/target/cfg_select/cfg_select_edge_cases.rs index dec05d032e316..ea6eaf9205693 100644 --- a/src/tools/rustfmt/tests/target/cfg_select_edge_cases.rs +++ b/src/tools/rustfmt/tests/target/cfg_select/cfg_select_edge_cases.rs @@ -86,10 +86,12 @@ fn cfg_select_comments_that_might_get_lost() { } } cfg_select! { - _ => {{ x }} + _ => + /* after => */ + {{ x }} } cfg_select! { - _ => {{ x }} + _ /* before arrow */ => {{ x }} } cfg_select! { @@ -109,6 +111,100 @@ fn cfg_select_comments_that_might_get_lost() { } /* d */ }} } + + cfg_select! { + _ => { + { x } /* after */ + } + } + + cfg_select! { + _ => { + { x } // after newline + } + } + + cfg_select! { + _ => + /* between */ + {{ x }} + } + + cfg_select! { + _ => + // between trailing + {{ x }} + } + + // Trailing comma + cfg_select! { + _ => + /* between */ + {{ x }}, + } + cfg_select! { + _ => + /* between */ + {{ + a; + b + }}, + } + + cfg_select! { + _ => + /* between */ + {{ + a; + b + }} + } + + cfg_select! { + _ => + /* multi + line */ + {{ x }} + } + + // Comments before `=>` + cfg_select! { + _ /* before arrow */ => {{ x }} + _ /* before arrow */ => x, + _ /* before arrow */ => + /* after arrow */ + {{ x }} + all(target_os = "linux", target_arch = "x86_64", target_env = "gnu") + /* long comment before arrow */ => {{ x }} + _ /* before arrow */ => {} + } + + cfg_select! { + // Not formatted: a line comment before `=>`. + c // before arrow + => x, + } + + cfg_select! { + _ => x /* before comma */, + } + + cfg_select! { + _ => {{ x }} /* before comma */, + } + + cfg_select! { + a => b, + } + + cfg_select! { + _ => xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx /* too long */, + } + + cfg_select! { + _ => x // trailing newline + , + } } fn other_cfg_select_cases() { @@ -288,6 +384,41 @@ fn other_cfg_select_cases() { || {} } }; + + cfg_select! { + _ => + /* before attr */ + #[attr] + { + z + } + } + + cfg_select! { + _ => + #[attr] /* after attr */ + { + z + } + } + + cfg_select! { + _ => + // line comment before attr + #[attr] + { + z + } + } + + cfg_select! { + _ => + /* before attr */ + #[attr] /* after attr */ + { + z + } + } } fn long_predicate() { diff --git a/src/tools/rustfmt/tests/target/cfg_select_stable.rs b/src/tools/rustfmt/tests/target/cfg_select/cfg_select_stable.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select_stable.rs rename to src/tools/rustfmt/tests/target/cfg_select/cfg_select_stable.rs diff --git a/src/tools/rustfmt/tests/target/cfg-select-valid-then-invalid-item-error-count-leak.rs b/src/tools/rustfmt/tests/target/cfg_select/cfg_select_valid_then_invalid_item_error_count_leak.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg-select-valid-then-invalid-item-error-count-leak.rs rename to src/tools/rustfmt/tests/target/cfg_select/cfg_select_valid_then_invalid_item_error_count_leak.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/control_brace_style_always_next_line.rs b/src/tools/rustfmt/tests/target/cfg_select/control_brace_style_always_next_line.rs new file mode 100644 index 0000000000000..d0a8880d97bd7 --- /dev/null +++ b/src/tools/rustfmt/tests/target/cfg_select/control_brace_style_always_next_line.rs @@ -0,0 +1,132 @@ +//@ rustfmt-unstable: true +//@ rustfmt-edition: 2024 +//@ rustfmt-control_brace_style: AlwaysNextLine + +cfg_select! { + _ => x, +} + +cfg_select! { + _ => x, +} + +cfg_select! { + _ => + {{ x }} +} + +cfg_select! { + _ => + {{ x }} +} + +cfg_select! { + _ => + unsafe { x }, +} + +cfg_select! { + _ => + {unsafe { x }} +} + +cfg_select! { + _ => + // line comment + {{ x }} +} + +cfg_select! { + _ => + // line comment + { + a; + b + } +} + +cfg_select! { + _ => + /* after */ + {{ x }} +} + +cfg_select! { + _ => + /* after */ + { + a; + b + } +} + +cfg_select! { + _ => + /* after + multiline */ + {{ x }} +} + +cfg_select! { + _ => + /* after + multiline */ + { + a; + b + } +} + +cfg_select! { + _ => + /* after */ + {{ x }} +} + +cfg_select! { + _ => + /* after */ + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long but brace should fit ---------------------------------- */ => + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long but shouldn't change next next line --------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => + {{ ThisLineIsShort }} +} diff --git a/src/tools/rustfmt/tests/target/cfg_select/control_brace_style_always_same_line.rs b/src/tools/rustfmt/tests/target/cfg_select/control_brace_style_always_same_line.rs new file mode 100644 index 0000000000000..827b579509d84 --- /dev/null +++ b/src/tools/rustfmt/tests/target/cfg_select/control_brace_style_always_same_line.rs @@ -0,0 +1,127 @@ +//@ rustfmt-unstable: true +//@ rustfmt-control_brace_style: AlwaysSameLine +// ^ NB: default value + +cfg_select! { + _ => x, +} + +cfg_select! { + _ => x, +} + +cfg_select! { + _ => {{ x }} +} + +cfg_select! { + _ => {{ x }} +} + +cfg_select! { + _ => unsafe { x }, +} + +cfg_select! { + _ => {unsafe { x }} +} + +cfg_select! { + _ => + // line comment + {{ x }} +} + +cfg_select! { + _ => + // line comment + { + a; + b + } +} + +cfg_select! { + _ => + /* after */ + {{ x }} +} + +cfg_select! { + _ => + /* after */ + { + a; + b + } +} + +cfg_select! { + _ => + /* after + multiline */ + {{ x }} +} + +cfg_select! { + _ => + /* after + multiline */ + { + a; + b + } +} + +cfg_select! { + _ => + /* after */ + {{ x }} +} + +cfg_select! { + _ => + /* after */ + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long but brace should fit ---------------------------------- */ => { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => + { + a; + b + } +} + +cfg_select! { + _ /* this comment is _very_ long but shouldn't change next next line --------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 101 columns incl. arrow ------------------- */ => + {{ ThisLineIsShort }} +} + +cfg_select! { + _ /* this comment is _very_ long and adds up to 100 columns itself -------------------------- */ => + {{ ThisLineIsShort }} +} diff --git a/src/tools/rustfmt/tests/target/issue_7045.rs b/src/tools/rustfmt/tests/target/cfg_select/issue_7045.rs similarity index 100% rename from src/tools/rustfmt/tests/target/issue_7045.rs rename to src/tools/rustfmt/tests/target/cfg_select/issue_7045.rs diff --git a/src/tools/rustfmt/tests/target/issue_7088_stable.rs b/src/tools/rustfmt/tests/target/cfg_select/issue_7088_stable.rs similarity index 100% rename from src/tools/rustfmt/tests/target/issue_7088_stable.rs rename to src/tools/rustfmt/tests/target/cfg_select/issue_7088_stable.rs diff --git a/src/tools/rustfmt/tests/target/issue_7088_unstable.rs b/src/tools/rustfmt/tests/target/cfg_select/issue_7088_unstable.rs similarity index 100% rename from src/tools/rustfmt/tests/target/issue_7088_unstable.rs rename to src/tools/rustfmt/tests/target/cfg_select/issue_7088_unstable.rs diff --git a/src/tools/rustfmt/tests/target/issue_7198.rs b/src/tools/rustfmt/tests/target/cfg_select/issue_7198.rs similarity index 100% rename from src/tools/rustfmt/tests/target/issue_7198.rs rename to src/tools/rustfmt/tests/target/cfg_select/issue_7198.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/issue_7209.rs b/src/tools/rustfmt/tests/target/cfg_select/issue_7209.rs new file mode 100644 index 0000000000000..4c06baa145027 --- /dev/null +++ b/src/tools/rustfmt/tests/target/cfg_select/issue_7209.rs @@ -0,0 +1,11 @@ +//@ rustfmt-unstable: true +//@ rustfmt-edition: 2024 + +fn gettid() -> u64 { + cfg_select! { + any(target_os = "solaris", target_os = "illumos") => { + // On Solaris and Illumos, the `pthread_t` is the OS TID. + unsafe { libc::pthread_self() as u64 } + } + } +} diff --git a/src/tools/rustfmt/tests/target/cfg_select/format_me_please_1.rs b/src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_1.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select/format_me_please_1.rs rename to src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_1.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/format_me_please_2.rs b/src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_2.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select/format_me_please_2.rs rename to src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_2.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/format_me_please_3.rs b/src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_3.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select/format_me_please_3.rs rename to src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_3.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/format_me_please_4.rs b/src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_4.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select/format_me_please_4.rs rename to src/tools/rustfmt/tests/target/cfg_select_multifile/format_me_please_4.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/lib.rs b/src/tools/rustfmt/tests/target/cfg_select_multifile/lib.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select/lib.rs rename to src/tools/rustfmt/tests/target/cfg_select_multifile/lib.rs diff --git a/src/tools/rustfmt/tests/target/cfg_select/lib2.rs b/src/tools/rustfmt/tests/target/cfg_select_multifile/lib2.rs similarity index 100% rename from src/tools/rustfmt/tests/target/cfg_select/lib2.rs rename to src/tools/rustfmt/tests/target/cfg_select_multifile/lib2.rs diff --git a/src/tools/rustfmt/tests/target/field-representing-types.rs b/src/tools/rustfmt/tests/target/field-representing-types.rs index a31ccbfb461f2..c5b400c6b3442 100644 --- a/src/tools/rustfmt/tests/target/field-representing-types.rs +++ b/src/tools/rustfmt/tests/target/field-representing-types.rs @@ -1,2 +1,4 @@ -type FRT = builtin # field_of(Type, ident); -type FRT2 = builtin # field_of(Type, ident); +//@ rustfmt-edition: 2021 + +type FRT = k#field_of(Type, ident); +type FRT2 = k#field_of(Type, ident); diff --git a/src/tools/rustfmt/tests/target/issue-6105.rs b/src/tools/rustfmt/tests/target/issue-6105.rs index 1eb0ce89f7812..cb73fc6042e24 100644 --- a/src/tools/rustfmt/tests/target/issue-6105.rs +++ b/src/tools/rustfmt/tests/target/issue-6105.rs @@ -1 +1,3 @@ -const _: () = builtin # offset_of(x, x); +//@ rustfmt-edition: 2021 + +const _: () = k#offset_of(x, x); diff --git a/src/tools/rustfmt/tests/target/issue-6651/custom_width.rs b/src/tools/rustfmt/tests/target/issue-6651/custom_width.rs index dfe747871018f..6bdfb562f5386 100644 --- a/src/tools/rustfmt/tests/target/issue-6651/custom_width.rs +++ b/src/tools/rustfmt/tests/target/issue-6651/custom_width.rs @@ -16,11 +16,6 @@ macro_rules! medium { macro_rules! long { () => { - m!( - aaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbb, - cccccccccccccccc, - ddddddddddddddd - ); + m!(aaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbb, cccccccccccccccc, ddddddddddddddd); }; } diff --git a/src/tools/rustfmt/tests/target/issue_6069.rs b/src/tools/rustfmt/tests/target/issue_6069.rs index d866ce7c646e3..febd840880a36 100644 --- a/src/tools/rustfmt/tests/target/issue_6069.rs +++ b/src/tools/rustfmt/tests/target/issue_6069.rs @@ -1,3 +1,4 @@ // `Foó` as written here ends with ASCII 6F `'o'` followed by `'\u{0301}'` COMBINING ACUTE ACCENT. -// The compiler normalizes that combination to NFC form, `'\u{00F3}'` LATIN SMALL LETTER O WITH ACUTE. +// The compiler normalizes that combination to NFC form, `'\u{00F3}'` +// LATIN SMALL LETTER O WITH ACUTE. trait Foó: Bar {} diff --git a/src/tools/rustfmt/tests/target/issue_6159.rs b/src/tools/rustfmt/tests/target/issue_6159.rs index 49fd539d3ef5a..35047aadcec6b 100644 --- a/src/tools/rustfmt/tests/target/issue_6159.rs +++ b/src/tools/rustfmt/tests/target/issue_6159.rs @@ -1,3 +1,5 @@ +//@ rustfmt-edition: 2021 + fn main() { - builtin # type_ascribe(10, usize) + k#type_ascribe(10, usize) } diff --git a/src/tools/rustfmt/triagebot.toml b/src/tools/rustfmt/triagebot.toml index de28ad00a4272..7197066a41a98 100644 --- a/src/tools/rustfmt/triagebot.toml +++ b/src/tools/rustfmt/triagebot.toml @@ -13,6 +13,7 @@ allow-unauthenticated = [ "E-*", "F-*", "I-*", + "llm-assisted", "needs-rfc", "needs-triage", "regression-*", diff --git a/tests/assembly-llvm/cstring-merging.rs b/tests/assembly-llvm/cstring-merging.rs index 9c1af4ebb4c05..e198a49c52216 100644 --- a/tests/assembly-llvm/cstring-merging.rs +++ b/tests/assembly-llvm/cstring-merging.rs @@ -14,7 +14,7 @@ use std::ffi::CStr; #[unsafe(no_mangle)] static CSTR: &[u8; 4] = b"foo\0"; -// CHECK-NOT: .section +// CHECK: .section .rodata.str1.{{[12]}},"aMS" // CHECK: {{(\.L|\$)}}anon.{{.+}}: // CHECK-NEXT: .{{asciz|string}} "bar" #[unsafe(no_mangle)] diff --git a/tests/assembly-llvm/static-relocation-model.rs b/tests/assembly-llvm/static-relocation-model.rs index a47681f4532a9..66bc992219527 100644 --- a/tests/assembly-llvm/static-relocation-model.rs +++ b/tests/assembly-llvm/static-relocation-model.rs @@ -47,7 +47,8 @@ pub fn peach() -> u8 { // x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] // x64-NEXT: {{movb|movzbl}} (%[[REG]]), %{{[a-z0-9]+}} // A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA -// A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] +// A64-NEXT: add [[REG2]], [[REG2]], :lo12:EXOCHORDA +// A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]]{{\]}} #[no_mangle] pub fn mango() -> u8 { unsafe { *EXOCHORDA } diff --git a/tests/codegen-llvm/async-fn-cold-attr.rs b/tests/codegen-llvm/async-fn-cold-attr.rs new file mode 100644 index 0000000000000..3f4925d9208d4 --- /dev/null +++ b/tests/codegen-llvm/async-fn-cold-attr.rs @@ -0,0 +1,51 @@ +// Checks that `#[cold]` on `async fn`s and async closures applies to the coroutine holding their +// body (i.e. the `Future::poll` implementation), in addition to the function or closure that +// constructs it. +// +//@ edition: 2024 +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] +#![feature(stmt_expr_attributes)] + +use std::future::Future; +use std::pin::pin; +use std::task::Context; + +// CHECK: ; async_fn_cold_attr::cold{{$}} +// CHECK-NEXT: ; Function Attrs: cold +// CHECK: ; async_fn_cold_attr::cold::{closure#0} +// CHECK-NEXT: ; Function Attrs: cold +#[cold] +pub async fn cold() {} + +// CHECK: ; async_fn_cold_attr::not_cold::{closure#0} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: cold +// CHECK-SAME: {{$}} +pub async fn not_cold() {} + +pub struct S; + +impl S { + // CHECK: ; ::method{{$}} + // CHECK-NEXT: ; Function Attrs: cold + // CHECK: ; ::method::{closure#0} + // CHECK-NEXT: ; Function Attrs: cold + #[cold] + pub async fn method(&self) {} +} + +// CHECK: ; async_fn_cold_attr::poll_all{{$}} +pub fn poll_all(cx: &mut Context<'_>) { + let _ = pin!(cold()).poll(cx); + let _ = pin!(not_cold()).poll(cx); + let _ = pin!(S.method()).poll(cx); + + // CHECK: ; async_fn_cold_attr::poll_all::{closure#0}{{$}} + // CHECK-NEXT: ; Function Attrs: cold + // CHECK: ; async_fn_cold_attr::poll_all::{closure#0}::{closure#0}:: + // CHECK-NEXT: ; Function Attrs: cold + let closure = #[cold] + async || {}; + let _ = pin!(closure()).poll(cx); +} diff --git a/tests/codegen-llvm/async-fn-inline-always-target-feature.rs b/tests/codegen-llvm/async-fn-inline-always-target-feature.rs new file mode 100644 index 0000000000000..83e635c03a50d --- /dev/null +++ b/tests/codegen-llvm/async-fn-inline-always-target-feature.rs @@ -0,0 +1,32 @@ +// `#[inline(always)]` on an `async fn` applies to its body coroutine (#129347). Unlike a closure +// marked `#[inline(always)]`, that coroutine is never inlined into the function it was written +// in, so it must still inherit that function's `#[target_feature]`s. +// +//@ revisions: x86_64 aarch64 +//@[x86_64] only-x86_64 +//@[aarch64] only-aarch64 +//@ edition: 2024 +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] + +use std::future::Future; +use std::pin::pin; +use std::task::{Context, Waker}; + +// CHECK: ; async_fn_inline_always_target_feature::always::{closure#0} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}} #[[ATTRS:[0-9]+]] +#[inline(always)] +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "avx2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "sha3"))] +pub async fn always() {} + +#[cfg_attr(target_arch = "x86_64", target_feature(enable = "avx2"))] +#[cfg_attr(target_arch = "aarch64", target_feature(enable = "sha3"))] +pub fn poll_always() { + let mut cx = Context::from_waker(Waker::noop()); + let _ = pin!(always()).poll(&mut cx); +} + +// x86_64: attributes #[[ATTRS]] = {{{.*}}"target-features"="{{[^"]*}}+avx2 +// aarch64: attributes #[[ATTRS]] = {{{.*}}"target-features"="{{[^"]*}}+sha3 diff --git a/tests/codegen-llvm/async-fn-inline-attr.rs b/tests/codegen-llvm/async-fn-inline-attr.rs new file mode 100644 index 0000000000000..d97300dd6046c --- /dev/null +++ b/tests/codegen-llvm/async-fn-inline-attr.rs @@ -0,0 +1,71 @@ +// Checks that inline attributes on `async fn`s and async closures apply to the coroutine holding +// their body (i.e. the `Future::poll` implementation) rather than to the function or closure that +// merely constructs it. See #129347. +// +//@ edition: 2024 +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no +#![crate_type = "lib"] +#![feature(stmt_expr_attributes)] + +use std::future::Future; +use std::pin::pin; +use std::task::Context; + +// CHECK: ; async_fn_inline_attr::never{{$}} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: noinline +// CHECK-SAME: {{$}} +// CHECK: ; async_fn_inline_attr::never::{closure#0} +// CHECK-NEXT: ; Function Attrs: noinline +#[inline(never)] +pub async fn never() {} + +// CHECK: ; async_fn_inline_attr::always{{$}} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: alwaysinline +// CHECK-SAME: {{$}} +// CHECK: ; async_fn_inline_attr::always::{closure#0} +// CHECK-NEXT: ; Function Attrs: alwaysinline +#[inline(always)] +pub async fn always() {} + +// The body coroutine would get an inline hint regardless, like all closures. +// CHECK: ; async_fn_inline_attr::hint{{$}} +// CHECK-NEXT: ; Function Attrs: +// CHECK-NOT: inlinehint +// CHECK-SAME: {{$}} +// CHECK: ; async_fn_inline_attr::hint::{closure#0} +// CHECK-NEXT: ; Function Attrs: inlinehint +#[inline] +pub async fn hint() {} + +pub struct S; + +impl S { + // CHECK: ; ::method{{$}} + // CHECK-NEXT: ; Function Attrs: + // CHECK-NOT: noinline + // CHECK-SAME: {{$}} + // CHECK: ; ::method::{closure#0} + // CHECK-NEXT: ; Function Attrs: noinline + #[inline(never)] + pub async fn method(&self) {} +} + +// CHECK: ; async_fn_inline_attr::poll_all{{$}} +pub fn poll_all(cx: &mut Context<'_>) { + let _ = pin!(never()).poll(cx); + let _ = pin!(always()).poll(cx); + let _ = pin!(hint()).poll(cx); + let _ = pin!(S.method()).poll(cx); + + // CHECK: ; async_fn_inline_attr::poll_all::{closure#0}{{$}} + // CHECK-NEXT: ; Function Attrs: + // CHECK-NOT: noinline + // CHECK-SAME: {{$}} + // CHECK: ; async_fn_inline_attr::poll_all::{closure#0}::{closure#0}:: + // CHECK-NEXT: ; Function Attrs: noinline + let closure = #[inline(never)] + async || {}; + let _ = pin!(closure()).poll(cx); +} diff --git a/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs b/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs index 64bc58e1df7af..f43566ba88118 100644 --- a/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs +++ b/tests/codegen-llvm/debuginfo-generic-closure-env-names.rs @@ -22,13 +22,13 @@ //@ edition: 2021 // non_generic_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], -// CHECK: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure" +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], +// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], +// CHECK-DAG: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure" -// CHECK: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure" -// CHECK: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function" -// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block" +// CHECK-DAG: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure" +// CHECK-DAG: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function" +// CHECK-DAG: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block" // function_containing_closure() // NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index 43ee290d3a058..135c7e32b4a5d 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -17,7 +17,7 @@ unsafe extern "C" { // PIE-NOT: dso_local // DIRECT-SAME: dso_local // INDIRECT-NOT: dso_local - // CHECK-SAME: global i32 + // CHECK-SAME: global [4 x i8] safe static VAR: i32; // When "linkage" is used, we generate an indirection global. diff --git a/tests/codegen-llvm/thread-local.rs b/tests/codegen-llvm/thread-local.rs index 70b655fd5cf61..a3584154e079d 100644 --- a/tests/codegen-llvm/thread-local.rs +++ b/tests/codegen-llvm/thread-local.rs @@ -16,8 +16,8 @@ use std::cell::Cell; thread_local!(static A: Cell = const { Cell::new(1) }); -// CHECK: [[TLS_AUX:@.+]] = external thread_local{{.*}} global i64 // CHECK: [[TLS:@.+]] = internal thread_local{{.*}} global +// CHECK: [[TLS_AUX:@.+]] = external thread_local{{.*}} global [8 x i8] // CHECK-LABEL: @get #[no_mangle] diff --git a/tests/crashes/158773.rs b/tests/crashes/158773.rs deleted file mode 100644 index 3020ab6206e4b..0000000000000 --- a/tests/crashes/158773.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #158773 -//@ needs-rustc-debug-assertions -//@ compile-flags: -Znext-solver=globally -trait HasLifetime { - type AtLifetime<'a>; -} - -pub struct ExistentialLifetime(S::AtLifetime<'static>); - -impl ExistentialLifetime { - fn new() -> ExistentialLifetime { - ExistentialLifetime(ExistentialLifetime(())) - } -} - -fn main() {} diff --git a/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs b/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs index eb1baea93dc00..38669eb1a21d7 100644 --- a/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs +++ b/tests/run-make/dynamic-loading-cdylib/load_and_unload.rs @@ -48,6 +48,8 @@ mod libloading { use std::ffi::{c_char, c_int, c_void}; const RTLD_NOW: c_int = 2; + #[cfg(target_os = "aix")] + const RTLD_MEMBER: c_int = 0x00040000; fn cstr_null(s: &str) -> Vec { assert!(!s.as_bytes().contains(&0), "string must not contain interior NUL"); @@ -58,10 +60,17 @@ mod libloading { #[cfg(target_os = "macos")] let filename = cstr_null(&format!("lib{}.dylib", lib_name)); - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "aix")] + let filename = cstr_null(&format!("./lib{0}.a(lib{0}.so)", lib_name)); + + #[cfg(not(any(target_os = "macos", target_os = "aix")))] let filename = cstr_null(&format!("./lib{}.so", lib_name)); - let handle = unsafe { dlopen(filename.as_ptr(), RTLD_NOW) }; + let flags = RTLD_NOW; + #[cfg(target_os = "aix")] + let flags = flags | RTLD_MEMBER; + + let handle = unsafe { dlopen(filename.as_ptr(), flags) }; if handle.is_null() { None } else { Some(handle) } } diff --git a/tests/run-make/dynamic-loading-cdylib/rmake.rs b/tests/run-make/dynamic-loading-cdylib/rmake.rs index 975722da75d6b..b931863b694a8 100644 --- a/tests/run-make/dynamic-loading-cdylib/rmake.rs +++ b/tests/run-make/dynamic-loading-cdylib/rmake.rs @@ -5,21 +5,29 @@ // - `foo.rs` is a cdylib. // - `load_and_unload.rs` is a binary that loads and unloads the cdylib. // -// This test is ignored on musl hosts because musl's dlclose is a no-op and -// therefore destructors won't run when the library is unloaded. -// See https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries //@ ignore-cross-compile -//@ ignore-musl use run_make_support::{diff, run_with_args, rustc}; +// On musl and AIX, `dlclose` does not invoke TLS destructors upon unloading, +// so only the `load_only` case is tested on those platforms. +// +// Reference for musl: +// https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries + +#[cfg(any(target_env = "musl", target_os = "aix"))] +const TEST_MODES: &[&str] = &["load_only"]; + +#[cfg(not(any(target_env = "musl", target_os = "aix")))] +const TEST_MODES: &[&str] = &["unload", "load_only"]; + fn main() { rustc().input("foo.rs").run(); rustc().crate_type("bin").crate_name("load_and_unload_bin").input("load_and_unload.rs").run(); - for command_arg in ["unload", "load_only"] { + for command_arg in TEST_MODES { let out_raw = run_with_args("load_and_unload_bin", &[command_arg]).stdout_utf8(); #[cfg(windows)] diff --git a/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr b/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr index 923972d02b713..f8d9b80ddbf62 100644 --- a/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr +++ b/tests/ui/associated-types/dyn-impl-missing-assoc-type-ice-152668.stderr @@ -48,6 +48,11 @@ LL | fn sub(self, rhs: Self) -> Self::Output {} found unit type `()` = help: consider constraining the associated type `<(dyn Vector2 + 'static) as Sub>::Output` to `()` or calling a method that returns `<(dyn Vector2 + 'static) as Sub>::Output` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: consider returning one of these bindings + --> $DIR/dyn-impl-missing-assoc-type-ice-152668.rs:10:12 + | +LL | fn sub(self, rhs: Self) -> Self::Output {} + | ^^^^ ^^^ error[E0277]: the size for values of type `(dyn Vector2 + 'static)` cannot be known at compilation time --> $DIR/dyn-impl-missing-assoc-type-ice-152668.rs:10:12 diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs index 33324685a84f4..f84f0bcbd34d4 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -33,9 +33,9 @@ pub fn e() {} //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` //~| ERROR: expected identifier, found keyword `unsafe` -//~| ERROR: malformed lint attribute input -//~| ERROR: malformed lint attribute input -//~| ERROR: malformed lint attribute input +//~| ERROR: malformed +//~| ERROR: malformed +//~| ERROR: malformed pub fn f() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 04e8c4d2dd453..cd73156eff453 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -25,11 +25,13 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[allow(dead_code)]` for `dead_code` error: the `proc_macro` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/proc-unsafe-attributes.rs:1:10 @@ -85,12 +87,13 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `proc_macro` is not an unsafe attribute @@ -176,15 +179,15 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(allow(r#unsafe(dead_code)))] | ++ -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/proc-unsafe-attributes.rs:29:16 | LL | #[unsafe(allow(unsafe(dead_code)))] - | ^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 21 previous errors -Some errors have detailed explanations: E0452, E0565. -For more information about an error, try `rustc --explain E0452`. +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr index 114c37188a9ef..ff82a449d83ba 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.deduplicate.stderr @@ -1,4 +1,4 @@ -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr index 66d0d94c0e815..3c7ce1686080c 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.duplicate.stderr @@ -1,4 +1,4 @@ -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] @@ -20,7 +20,7 @@ LL | #[derive(Unresolved)] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] @@ -29,7 +29,7 @@ LL | #[deny("literal")] = help: try using `#[deny(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/deduplicate-diagnostics.rs:10:8 | LL | #[deny("literal")] diff --git a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs index b070ec0f7dd93..437ed20acbeb9 100644 --- a/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs +++ b/tests/ui/diagnostic-flags/deduplicate-diagnostics.rs @@ -7,7 +7,7 @@ //[duplicate]~| ERROR cannot find derive macro `Unresolved` in this scope struct S; -#[deny("literal")] //~ ERROR expected a lint, found literal - //[duplicate]~| ERROR expected a lint, found literal - //[duplicate]~| ERROR expected a lint, found literal +#[deny("literal")] //~ ERROR malformed + //[duplicate]~| ERROR malformed + //[duplicate]~| ERROR malformed fn main() {} diff --git a/tests/ui/error-codes/E0452.rs b/tests/ui/error-codes/E0452.rs index 4e5a6c9301467..6a0437df7b14e 100644 --- a/tests/ui/error-codes/E0452.rs +++ b/tests/ui/error-codes/E0452.rs @@ -1,8 +1,8 @@ -#![allow(foo = "")] //~ ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 +#![allow(foo = "")] //~ ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed fn main() { } diff --git a/tests/ui/error-codes/E0452.stderr b/tests/ui/error-codes/E0452.stderr index c20429e363dda..c34d9a2a01b28 100644 --- a/tests/ui/error-codes/E0452.stderr +++ b/tests/ui/error-codes/E0452.stderr @@ -1,49 +1,55 @@ -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint + | + = help: for example, write `#[allow(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/E0452.rs:1:10 | LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument + | ^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.rs b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs deleted file mode 100644 index 832bb5a96bc3d..0000000000000 --- a/tests/ui/feature-gates/feature-gate-builtin_syntax.rs +++ /dev/null @@ -1,7 +0,0 @@ -struct Foo { - v: u8, - w: u8, -} -fn main() { - builtin # offset_of(Foo, v); //~ ERROR `builtin #` syntax is unstable -} diff --git a/tests/ui/feature-gates/feature-gate-internal_syntax.rs b/tests/ui/feature-gates/feature-gate-internal_syntax.rs new file mode 100644 index 0000000000000..5b4293d900923 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-internal_syntax.rs @@ -0,0 +1,10 @@ +//@ edition: 2021.. +#![feature(forced_keywords)] + +struct Foo { + v: u8, + w: u8, +} +fn main() { + k#offset_of(Foo, v); //~ ERROR this syntax is internal +} diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr b/tests/ui/feature-gates/feature-gate-internal_syntax.stderr similarity index 56% rename from tests/ui/feature-gates/feature-gate-builtin_syntax.stderr rename to tests/ui/feature-gates/feature-gate-internal_syntax.stderr index 297363b3de711..9db1a51e0d999 100644 --- a/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr +++ b/tests/ui/feature-gates/feature-gate-internal_syntax.stderr @@ -1,11 +1,11 @@ -error[E0658]: `builtin #` syntax is unstable - --> $DIR/feature-gate-builtin_syntax.rs:6:15 +error[E0658]: this syntax is internal + --> $DIR/feature-gate-internal_syntax.rs:9:5 | -LL | builtin # offset_of(Foo, v); - | ^^^^^^^^^ +LL | k#offset_of(Foo, v); + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #110680 for more information - = help: add `#![feature(builtin_syntax)]` to the crate attributes to enable + = help: add `#![feature(internal_syntax)]` 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 1 previous error diff --git a/tests/ui/field_representing_types/invalid.next.stderr b/tests/ui/field_representing_types/invalid.next.stderr index 52872001b4dee..82b2aa81451ab 100644 --- a/tests/ui/field_representing_types/invalid.next.stderr +++ b/tests/ui/field_representing_types/invalid.next.stderr @@ -33,7 +33,7 @@ error: offset_of expects dot-separated field and variant names LL | let _: field_of!(Enum, Variant..field); | ^^^^^^^^^^^^^^ -error: `field_of!` expects dot-separated field and variant names +error: `field_of` expects dot-separated field and variant names --> $DIR/invalid.rs:28:12 | LL | let _: field_of!(Enum, Variant..field); @@ -48,7 +48,7 @@ error: offset_of expects dot-separated field and variant names LL | let _: field_of!(Struct, [42]); | ^^^^ -error: `field_of!` expects dot-separated field and variant names +error: `field_of` expects dot-separated field and variant names --> $DIR/invalid.rs:30:12 | LL | let _: field_of!(Struct, [42]); @@ -57,7 +57,7 @@ LL | let _: field_of!(Struct, [42]); | in this macro invocation | this macro call doesn't expand to a type -error: `field_of!` only supports a single field or a variant with a field +error: `field_of` only supports a single field or a variant with a field --> $DIR/invalid.rs:32:30 | LL | let _: field_of!(Struct, field1.field2.field3); diff --git a/tests/ui/field_representing_types/invalid.old.stderr b/tests/ui/field_representing_types/invalid.old.stderr index 52872001b4dee..82b2aa81451ab 100644 --- a/tests/ui/field_representing_types/invalid.old.stderr +++ b/tests/ui/field_representing_types/invalid.old.stderr @@ -33,7 +33,7 @@ error: offset_of expects dot-separated field and variant names LL | let _: field_of!(Enum, Variant..field); | ^^^^^^^^^^^^^^ -error: `field_of!` expects dot-separated field and variant names +error: `field_of` expects dot-separated field and variant names --> $DIR/invalid.rs:28:12 | LL | let _: field_of!(Enum, Variant..field); @@ -48,7 +48,7 @@ error: offset_of expects dot-separated field and variant names LL | let _: field_of!(Struct, [42]); | ^^^^ -error: `field_of!` expects dot-separated field and variant names +error: `field_of` expects dot-separated field and variant names --> $DIR/invalid.rs:30:12 | LL | let _: field_of!(Struct, [42]); @@ -57,7 +57,7 @@ LL | let _: field_of!(Struct, [42]); | in this macro invocation | this macro call doesn't expand to a type -error: `field_of!` only supports a single field or a variant with a field +error: `field_of` only supports a single field or a variant with a field --> $DIR/invalid.rs:32:30 | LL | let _: field_of!(Struct, field1.field2.field3); diff --git a/tests/ui/field_representing_types/invalid.rs b/tests/ui/field_representing_types/invalid.rs index 0d8c5d563401c..e0ba33dd4eb59 100644 --- a/tests/ui/field_representing_types/invalid.rs +++ b/tests/ui/field_representing_types/invalid.rs @@ -24,10 +24,10 @@ fn main() { let _: field_of!(Struct); //~ ERROR: unexpected end of macro invocation let _: field_of!(Struct,); //~ ERROR: unexpected end of macro invocation let _: field_of!(Struct, field, extra); //~ ERROR: no rules expected `extra` - // FIXME(FRTs): adjust error message to mention `field_of!` & prevent double errors + // FIXME(FRTs): adjust error message to mention `field_of` & prevent double errors let _: field_of!(Enum, Variant..field); //~ ERROR: offset_of expects dot-separated field and variant names - //~^ ERROR: `field_of!` expects dot-separated field and variant names + //~^ ERROR: `field_of` expects dot-separated field and variant names let _: field_of!(Struct, [42]); //~ ERROR: offset_of expects dot-separated field and variant names - //~^ ERROR: `field_of!` expects dot-separated field and variant names - let _: field_of!(Struct, field1.field2.field3); //~ ERROR: `field_of!` only supports a single field or a variant with a field + //~^ ERROR: `field_of` expects dot-separated field and variant names + let _: field_of!(Struct, field1.field2.field3); //~ ERROR: `field_of` only supports a single field or a variant with a field } diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr index 4a0991d0eb3cb..8015bc15f510c 100644 --- a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr @@ -11,6 +11,8 @@ LL | x = foo::<()>; | = note: expected fn item `fn(F) -> F {bar::}` found fn item `fn(()) -> () {foo::<()>}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn(Alias(No, Alias { kind: Opaque { def_id: DefId(0:8 ~ fn_def_opaque_coercion_to_fn_ptr[7fda]::F::{opaque#0}) }, args: [], .. })) -> Alias(No, Alias { kind: Opaque { def_id: DefId(0:8 ~ fn_def_opaque_coercion_to_fn_ptr[7fda]::F::{opaque#0}) }, args: [], .. })` error[E0308]: mismatched types --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:29:9 @@ -28,6 +30,8 @@ LL | x = foo::; | = note: expected fn item `fn(()) -> () {bar::<()>}` found fn item `fn(I) -> I {foo::}` + = note: different fn items have unique types, even if their signatures are the same + = help: consider casting both fn items to fn pointers using `as fn(())` help: use parentheses to call this function | LL | x = foo::(/* I */); diff --git a/tests/ui/force-inlining/invalid-async-cold.rs b/tests/ui/force-inlining/invalid-async-cold.rs new file mode 100644 index 0000000000000..f0a699ac1caa0 --- /dev/null +++ b/tests/ui/force-inlining/invalid-async-cold.rs @@ -0,0 +1,25 @@ +//@ edition: 2024 +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(gen_blocks)] +#![feature(rustc_attrs)] + +// `#[inline]` on an `async fn` or `gen fn` applies to its body coroutine, but +// `#[rustc_force_inline]` must not: it is already rejected on such functions, +// so it must not also be reported as incompatible with `#[cold]`, which both +// the function and its body coroutine get. + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +#[cold] +pub async fn async_cold() {} + +#[rustc_force_inline] +//~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function +#[cold] +pub gen fn gen_cold() {} + +pub fn caller() { + let _ = async_cold(); + let _ = gen_cold(); +} diff --git a/tests/ui/force-inlining/invalid-async-cold.stderr b/tests/ui/force-inlining/invalid-async-cold.stderr new file mode 100644 index 0000000000000..cc176458c0c13 --- /dev/null +++ b/tests/ui/force-inlining/invalid-async-cold.stderr @@ -0,0 +1,20 @@ +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid-async-cold.rs:12:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | pub async fn async_cold() {} + | ------------------------- `async`, `gen` or `async gen` function + +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid-async-cold.rs:17:1 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | pub gen fn gen_cold() {} + | --------------------- `async`, `gen` or `async gen` function + +error: aborting due to 2 previous errors + diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr index f9f39e34b658e..7339b9acaea56 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -6,8 +6,6 @@ LL | call(f, ()); | | | required by a bound introduced by this call | - = note: expected type with signature `for<'a> fn(<_ as ATC<'a>>::Type)` - found type parameter with signature `fn(())` note: required by a bound in `call` --> $DIR/issue-62529-3.rs:9:36 | diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.rs b/tests/ui/hygiene/unpretty-debug-lifetimes.rs index ee8be21b60d01..5f8a20281ab04 100644 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.rs +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.rs @@ -4,8 +4,15 @@ // Regression test for lifetime hygiene annotations in -Zunpretty=expanded,hygiene // Previously, lifetimes were missing the #N syntax context suffix. -// Don't break whenever Symbol numbering changes -//@ normalize-stdout: "\d+#" -> "0#" +// This test deliberately has no `.stdout` snapshot. The hygiene annotations +// embed `Symbol` indices, whose width feeds into the pretty-printer's line +// breaking, so the layout shifts whenever a `Symbol` gains or loses a digit. +// `normalize-stdout` can't help, because the layout is decided before +// normalization runs. Assert the property this test is about instead: the two +// `'a` share their text but carry different syntax contexts. +//@ dont-check-compiler-stdout +//@ check-stdout +//@ regex-error-pattern: f\s*/\*\s*\d+#0\s*\*/<'a\s*/\*\s*\d+#0\s*\*/,\s*'a\s*/\*\s*\d+#1\s*\*/ #![feature(decl_macro)] #![feature(no_core)] diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout deleted file mode 100644 index c75cc7b2179d3..0000000000000 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout +++ /dev/null @@ -1,33 +0,0 @@ -//@ check-pass -//@ compile-flags: -Zunpretty=expanded,hygiene - -// Regression test for lifetime hygiene annotations in -Zunpretty=expanded,hygiene -// Previously, lifetimes were missing the #N syntax context suffix. - -// Don't break whenever Symbol numbering changes -//@ normalize-stdout: "\d+#" -> "0#" - -#![feature /* 0#0 */(decl_macro /* 0#0 */)] -#![feature /* 0#0 */(no_core /* 0#0 */)] -#![no_core /* 0#0 */] - -macro lifetime_hygiene - /* - 0#0 - */ { - ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 - */>) => - { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} } -} -fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} - - -/* -Expansions: -crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root -crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "lifetime_hygiene") - -SyntaxContexts: -#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) -#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque) -*/ diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr index 5a8cc40d0276e..1f824bb23f0b7 100644 --- a/tests/ui/impl-trait/in-assoc-type.stderr +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -11,6 +11,10 @@ LL | fn foo(&self) -> >::Bar {} | = note: expected opaque type `<() as Foo<()>>::Bar` found unit type `()` +help: consider returning the local binding `self` + | +LL | fn foo(&self) -> >::Bar { self } + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/lint/lint-attribute-literals.rs b/tests/ui/lint/lint-attribute-literals.rs index 34a4757adec3c..7adec75210108 100644 --- a/tests/ui/lint/lint-attribute-literals.rs +++ b/tests/ui/lint/lint-attribute-literals.rs @@ -1,11 +1,11 @@ // Checks that lint attributes with literals have an explanatory error #[allow("literal")] -//~^ ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal +//~^ ERROR malformed +//~| ERROR malformed +//~| ERROR malformed #[deny(1.0)] -//~^ ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal -//~| ERROR expected a lint, found literal +//~^ ERROR malformed +//~| ERROR malformed +//~| ERROR malformed fn main() {} diff --git a/tests/ui/lint/lint-attribute-literals.stderr b/tests/ui/lint/lint-attribute-literals.stderr index 7434f8b5c5d4b..b06eac094f66d 100644 --- a/tests/ui/lint/lint-attribute-literals.stderr +++ b/tests/ui/lint/lint-attribute-literals.stderr @@ -1,4 +1,4 @@ -error: expected a lint, found literal +error: malformed `allow` attribute input --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -6,7 +6,7 @@ LL | #[allow("literal")] | = help: try using `#[allow(literal)]` -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] @@ -14,7 +14,7 @@ LL | #[deny(1.0)] | = help: for example, write `#[deny(dead_code)]` for `dead_code` -error: expected a lint, found literal +error: malformed `allow` attribute input --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -23,7 +23,7 @@ LL | #[allow("literal")] = help: try using `#[allow(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] @@ -32,7 +32,7 @@ LL | #[deny(1.0)] = help: for example, write `#[deny(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: malformed `allow` attribute input --> $DIR/lint-attribute-literals.rs:3:9 | LL | #[allow("literal")] @@ -41,7 +41,7 @@ LL | #[allow("literal")] = help: try using `#[allow(literal)]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: expected a lint, found literal +error: malformed `deny` attribute input --> $DIR/lint-attribute-literals.rs:7:8 | LL | #[deny(1.0)] diff --git a/tests/ui/lint/lint-malformed.rs b/tests/ui/lint/lint-malformed.rs index cf5570753d85d..5fd92170363f0 100644 --- a/tests/ui/lint/lint-malformed.rs +++ b/tests/ui/lint/lint-malformed.rs @@ -1,8 +1,8 @@ #![deny = "foo"] //~ ERROR malformed `deny` attribute input -#![allow(bar = "baz")] //~ ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute +#![allow(bar = "baz")] //~ ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed + //~| ERROR malformed fn main() { } diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr index 7be928de86985..ceb7fe105bcd3 100644 --- a/tests/ui/lint/lint-malformed.stderr +++ b/tests/ui/lint/lint-malformed.stderr @@ -1,31 +1,36 @@ -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[allow(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0539]: malformed `deny` attribute input @@ -49,23 +54,24 @@ LL - #![deny = "foo"] LL + #![deny(lint1, lint2, lint3, reason = "...")] | -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0452]: malformed lint attribute input +error: malformed `allow` attribute input --> $DIR/lint-malformed.rs:2:10 | LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^ not the name of a lint | + = help: for example, write `#[allow(dead_code)]` for `dead_code` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 7 previous errors -Some errors have detailed explanations: E0452, E0539. -For more information about an error, try `rustc --explain E0452`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/lint/pre-expansion-parsing.rs b/tests/ui/lint/pre-expansion-parsing.rs index 7cfc57ff4e903..11a55beb77d65 100644 --- a/tests/ui/lint/pre-expansion-parsing.rs +++ b/tests/ui/lint/pre-expansion-parsing.rs @@ -3,7 +3,7 @@ #[expect] // OK #[expect[wut]] // OK #[expect(expect)] // OK -#[expect(expect(expect))] //~ ERROR malformed lint attribute input +#[expect(expect(expect))] //~ ERROR malformed #[deny(({!}))] // OK #[expect[helix::]] // OK #[cfg(false)] diff --git a/tests/ui/lint/pre-expansion-parsing.stderr b/tests/ui/lint/pre-expansion-parsing.stderr index ecc8b7017d92d..651fd5d4c8f38 100644 --- a/tests/ui/lint/pre-expansion-parsing.stderr +++ b/tests/ui/lint/pre-expansion-parsing.stderr @@ -1,9 +1,10 @@ -error[E0452]: malformed lint attribute input +error: malformed `expect` attribute input --> $DIR/pre-expansion-parsing.rs:6:10 | LL | #[expect(expect(expect))] - | ^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[expect(dead_code)]` for `dead_code` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 38ad00da64cd7..4a0c458209ee6 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -8,14 +8,14 @@ //~^ ERROR malformed `warn` attribute input //~| NOTE expected a normal string literal, not a byte string literal #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] -//~^ ERROR malformed lint attribute -//~| NOTE bad attribute argument +//~^ ERROR malformed +//~| NOTE not the name of a lint #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] -//~^ ERROR malformed lint attribute -//~| NOTE bad attribute argument +//~^ ERROR malformed +//~| NOTE not the name of a lint #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] -//~^ ERROR malformed lint attribute -//~| NOTE bad attribute argument +//~^ ERROR malformed +//~| NOTE not the name of a lint #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] //~^ ERROR malformed lint attribute //~| NOTE reason in lint attribute must come last diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index d771366d6168e..3c52a0d8e25b4 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -29,23 +29,29 @@ LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condem | = note: expected a normal string literal, not a byte string literal -error[E0452]: malformed lint attribute input +error: malformed `warn` attribute input --> $DIR/reasons-erroneous.rs:10:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[warn(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: malformed `warn` attribute input --> $DIR/reasons-erroneous.rs:13:22 | LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[warn(dead_code)]` for `dead_code` -error[E0452]: malformed lint attribute input +error: malformed `warn` attribute input --> $DIR/reasons-erroneous.rs:16:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not the name of a lint + | + = help: for example, write `#[warn(dead_code)]` for `dead_code` error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:19:44 diff --git a/tests/ui/offload/check_config.fail.stderr b/tests/ui/offload/check_config.fail.stderr index 87df9d42bafd1..6f4ae31491d86 100644 --- a/tests/ui/offload/check_config.fail.stderr +++ b/tests/ui/offload/check_config.fail.stderr @@ -1,4 +1,4 @@ -error: using the offload feature requires -Z offload=.bc> +error: using the offload feature requires -Z offload=.ptx or .elf> error: using the offload feature requires -C lto=fat diff --git a/tests/ui/offload/check_config.rs b/tests/ui/offload/check_config.rs index 9865d36049a8f..d28d27d2c9d10 100644 --- a/tests/ui/offload/check_config.rs +++ b/tests/ui/offload/check_config.rs @@ -6,7 +6,7 @@ //@[pass] compile-flags: -Zunstable-options -Zoffload=Device -Clto=fat --emit=metadata //@[fail] compile-flags: -Clto=thin -//[fail]~? ERROR: using the offload feature requires -Z offload=.bc> +//[fail]~? ERROR: using the offload feature requires -Z offload=.ptx or .elf> //[fail]~? ERROR: using the offload feature requires -C lto=fat #![feature(gpu_offload)] diff --git a/tests/ui/offset-of/offset-of-builtin.rs b/tests/ui/offset-of/offset-of-builtin.rs deleted file mode 100644 index 6664c10f905ef..0000000000000 --- a/tests/ui/offset-of/offset-of-builtin.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![feature(builtin_syntax)] - -// For the exposed macro we already test these errors in the other files, -// but this test helps to make sure the builtin construct also errors. -// This has the same examples as offset-of-arg-count.rs - -fn main() { - builtin # offset_of(NotEnoughArguments); //~ ERROR expected one of -} -fn t1() { - builtin # offset_of(NotEnoughArgumentsWithAComma, ); //~ ERROR expected expression -} -fn t2() { - builtin # offset_of(S, f, too many arguments); //~ ERROR expected `)`, found `too` -} -fn t3() { - builtin # offset_of(S, f); // compiles fine -} -fn t4() { - builtin # offset_of(S, f.); //~ ERROR unexpected token -} -fn t5() { - builtin # offset_of(S, f.,); //~ ERROR unexpected token -} -fn t6() { - builtin # offset_of(S, f..); //~ ERROR offset_of expects dot-separated field and variant names -} -fn t7() { - builtin # offset_of(S, f..,); //~ ERROR offset_of expects dot-separated field and variant names -} - -struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-builtin.stderr b/tests/ui/offset-of/offset-of-builtin.stderr deleted file mode 100644 index 5917ee2936361..0000000000000 --- a/tests/ui/offset-of/offset-of-builtin.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `)` - --> $DIR/offset-of-builtin.rs:8:43 - | -LL | builtin # offset_of(NotEnoughArguments); - | ^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` - -error: expected expression, found `)` - --> $DIR/offset-of-builtin.rs:11:55 - | -LL | builtin # offset_of(NotEnoughArgumentsWithAComma, ); - | ^ expected expression - -error: expected `)`, found `too` - --> $DIR/offset-of-builtin.rs:14:31 - | -LL | builtin # offset_of(S, f, too many arguments); - | ^^^ expected `)` - | - = note: unexpected third argument to offset_of - -error: unexpected token: `)` - --> $DIR/offset-of-builtin.rs:20:30 - | -LL | builtin # offset_of(S, f.); - | ^ - -error: unexpected token: `,` - --> $DIR/offset-of-builtin.rs:23:30 - | -LL | builtin # offset_of(S, f.,); - | ^ - -error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-builtin.rs:26:28 - | -LL | builtin # offset_of(S, f..); - | ^^^ - -error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-builtin.rs:29:28 - | -LL | builtin # offset_of(S, f..,); - | ^^^ - -error: aborting due to 7 previous errors - diff --git a/tests/ui/offset-of/offset-of-tuple-field.rs b/tests/ui/offset-of/offset-of-tuple-field.rs index 02d41f91a2563..755d61d18b739 100644 --- a/tests/ui/offset-of/offset-of-tuple-field.rs +++ b/tests/ui/offset-of/offset-of-tuple-field.rs @@ -1,5 +1,3 @@ -#![feature(builtin_syntax)] - use std::mem::offset_of; fn main() { @@ -9,12 +7,6 @@ fn main() { offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_` //~| ERROR suffixes on a tuple index - builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2` - builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0` - builtin # offset_of((u8, u8), 01); //~ ERROR no field `01` - builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_` - //~| ERROR suffixes on a tuple index - offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2` offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2` offset_of!(((u8, u16), (u32, u16, u8)), 1.2); diff --git a/tests/ui/offset-of/offset-of-tuple-field.stderr b/tests/ui/offset-of/offset-of-tuple-field.stderr index 01622c5fa2da6..052e4b0596fd6 100644 --- a/tests/ui/offset-of/offset-of-tuple-field.stderr +++ b/tests/ui/offset-of/offset-of-tuple-field.stderr @@ -1,17 +1,11 @@ error: suffixes on a tuple index are invalid - --> $DIR/offset-of-tuple-field.rs:15:35 - | -LL | builtin # offset_of((u8, u8), 1_u8); - | ^^^^ invalid suffix `u8` - -error: suffixes on a tuple index are invalid - --> $DIR/offset-of-tuple-field.rs:9:26 + --> $DIR/offset-of-tuple-field.rs:7:26 | LL | offset_of!((u8, u8), 1_u8); | ^^^^ invalid suffix `u8` error[E0609]: no field `_0` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:6:26 + --> $DIR/offset-of-tuple-field.rs:4:26 | LL | offset_of!((u8, u8), _0); | ^^ @@ -23,7 +17,7 @@ LL + offset_of!((u8, u8), 0); | error[E0609]: no field `01` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:7:26 + --> $DIR/offset-of-tuple-field.rs:5:26 | LL | offset_of!((u8, u8), 01); | ^^ @@ -31,7 +25,7 @@ LL | offset_of!((u8, u8), 01); = note: available fields are: `0`, `1` error[E0609]: no field `1e2` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:8:26 + --> $DIR/offset-of-tuple-field.rs:6:26 | LL | offset_of!((u8, u8), 1e2); | ^^^ @@ -39,7 +33,7 @@ LL | offset_of!((u8, u8), 1e2); = note: available fields are: `0`, `1` error[E0609]: no field `1_` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:9:26 + --> $DIR/offset-of-tuple-field.rs:7:26 | LL | offset_of!((u8, u8), 1_u8); | ^^^^ @@ -50,48 +44,8 @@ LL - offset_of!((u8, u8), 1_u8); LL + offset_of!((u8, u8), 1); | -error[E0609]: no field `1e2` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:12:35 - | -LL | builtin # offset_of((u8, u8), 1e2); - | ^^^ - | - = note: available fields are: `0`, `1` - -error[E0609]: no field `_0` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:13:35 - | -LL | builtin # offset_of((u8, u8), _0); - | ^^ - | -help: a field with a similar name exists - | -LL - builtin # offset_of((u8, u8), _0); -LL + builtin # offset_of((u8, u8), 0); - | - -error[E0609]: no field `01` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:14:35 - | -LL | builtin # offset_of((u8, u8), 01); - | ^^ - | - = note: available fields are: `0`, `1` - -error[E0609]: no field `1_` on type `(u8, u8)` - --> $DIR/offset-of-tuple-field.rs:15:35 - | -LL | builtin # offset_of((u8, u8), 1_u8); - | ^^^^ - | -help: a field with a similar name exists - | -LL - builtin # offset_of((u8, u8), 1_u8); -LL + builtin # offset_of((u8, u8), 1); - | - error[E0609]: no field `2` on type `(u8, u16)` - --> $DIR/offset-of-tuple-field.rs:18:47 + --> $DIR/offset-of-tuple-field.rs:10:47 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); | ^ @@ -99,7 +53,7 @@ LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.2); = note: available fields are: `0`, `1` error[E0609]: no field `1e2` on type `(u8, u16)` - --> $DIR/offset-of-tuple-field.rs:19:47 + --> $DIR/offset-of-tuple-field.rs:11:47 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); | ^^^ @@ -107,11 +61,11 @@ LL | offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); = note: available fields are: `0`, `1` error[E0609]: no field `0` on type `u8` - --> $DIR/offset-of-tuple-field.rs:21:49 + --> $DIR/offset-of-tuple-field.rs:13:49 | LL | offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); | ^ -error: aborting due to 13 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs index ddbaee97b1bb0..be668d9e08946 100644 --- a/tests/ui/offset-of/offset-of-tuple.rs +++ b/tests/ui/offset-of/offset-of-tuple.rs @@ -1,4 +1,5 @@ -#![feature(builtin_syntax)] +//@ edition: 2021.. +#![feature(forced_keywords, internal_syntax)] use std::mem::offset_of; @@ -9,9 +10,9 @@ fn main() { offset_of!((u8, u8), 1 .); //~ ERROR unexpected token: `)` // We need to put these into curly braces, otherwise only one of the // errors will be emitted and the others suppressed. - { builtin # offset_of((u8, u8), +1) }; //~ ERROR leading `+` is not supported - { builtin # offset_of((u8, u8), 1.) }; //~ ERROR offset_of expects dot-separated field and variant names - { builtin # offset_of((u8, u8), 1 .) }; //~ ERROR unexpected token: `)` + { k#offset_of((u8, u8), +1) }; //~ ERROR leading `+` is not supported + { k#offset_of((u8, u8), 1.) }; //~ ERROR offset_of expects dot-separated field and variant names + { k#offset_of((u8, u8), 1 .) }; //~ ERROR unexpected token: `)` } type ComplexTup = (((u8, u8), u8), u8); @@ -26,14 +27,15 @@ fn nested() { offset_of!(ComplexTup, 0.0 . 1.); //~ ERROR unexpected token: `)` offset_of!(ComplexTup, 0.0. 1.); //~ ERROR unexpected token: `)` + // FIXME(fmease): Update comment. // Test for builtin too to ensure that the builtin syntax can also handle these cases // We need to put these into curly braces, otherwise only one of the // errors will be emitted and the others suppressed. - { builtin # offset_of(ComplexTup, 0.0.1.) }; //~ ERROR unexpected token: `)` - { builtin # offset_of(ComplexTup, 0 .0.1.) }; //~ ERROR unexpected token: `)` - { builtin # offset_of(ComplexTup, 0 . 0.1.) }; //~ ERROR unexpected token: `)` - { builtin # offset_of(ComplexTup, 0. 0.1.) }; //~ ERROR unexpected token: `)` - { builtin # offset_of(ComplexTup, 0.0 .1.) }; //~ ERROR unexpected token: `)` - { builtin # offset_of(ComplexTup, 0.0 . 1.) }; //~ ERROR unexpected token: `)` - { builtin # offset_of(ComplexTup, 0.0. 1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0.0.1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0 .0.1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0 . 0.1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0. 0.1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0.0 .1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0.0 . 1.) }; //~ ERROR unexpected token: `)` + { k#offset_of(ComplexTup, 0.0. 1.) }; //~ ERROR unexpected token: `)` } diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index f90f2db1c6c35..db46373449218 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -1,71 +1,71 @@ error: leading `+` is not supported - --> $DIR/offset-of-tuple.rs:12:37 + --> $DIR/offset-of-tuple.rs:13:29 | -LL | { builtin # offset_of((u8, u8), +1) }; - | ^ unexpected `+` +LL | { k#offset_of((u8, u8), +1) }; + | ^ unexpected `+` | help: try removing the `+` | -LL - { builtin # offset_of((u8, u8), +1) }; -LL + { builtin # offset_of((u8, u8), 1) }; +LL - { k#offset_of((u8, u8), +1) }; +LL + { k#offset_of((u8, u8), 1) }; | error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-tuple.rs:13:38 + --> $DIR/offset-of-tuple.rs:14:30 | -LL | { builtin # offset_of((u8, u8), 1.) }; - | ^ +LL | { k#offset_of((u8, u8), 1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:14:40 + --> $DIR/offset-of-tuple.rs:15:32 | -LL | { builtin # offset_of((u8, u8), 1 .) }; - | ^ +LL | { k#offset_of((u8, u8), 1 .) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:32:45 + --> $DIR/offset-of-tuple.rs:34:37 | -LL | { builtin # offset_of(ComplexTup, 0.0.1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0.0.1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:33:46 + --> $DIR/offset-of-tuple.rs:35:38 | -LL | { builtin # offset_of(ComplexTup, 0 .0.1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0 .0.1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:34:47 + --> $DIR/offset-of-tuple.rs:36:39 | -LL | { builtin # offset_of(ComplexTup, 0 . 0.1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0 . 0.1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:35:46 + --> $DIR/offset-of-tuple.rs:37:38 | -LL | { builtin # offset_of(ComplexTup, 0. 0.1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0. 0.1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:36:46 + --> $DIR/offset-of-tuple.rs:38:38 | -LL | { builtin # offset_of(ComplexTup, 0.0 .1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0.0 .1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:37:47 + --> $DIR/offset-of-tuple.rs:39:39 | -LL | { builtin # offset_of(ComplexTup, 0.0 . 1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0.0 . 1.) }; + | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:38:46 + --> $DIR/offset-of-tuple.rs:40:38 | -LL | { builtin # offset_of(ComplexTup, 0.0. 1.) }; - | ^ +LL | { k#offset_of(ComplexTup, 0.0. 1.) }; + | ^ error: no rules expected `+` - --> $DIR/offset-of-tuple.rs:6:26 + --> $DIR/offset-of-tuple.rs:7:26 | LL | offset_of!((u8, u8), +1); | ^ no rules expected this token in macro call @@ -75,61 +75,61 @@ note: while trying to match meta-variable `$fields:expr` = note: this macro expects a container type and a (nested) field path, like `offset_of!(Type, field)` error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-tuple.rs:7:26 + --> $DIR/offset-of-tuple.rs:8:26 | LL | offset_of!((u8, u8), -1); | ^^ error: offset_of expects dot-separated field and variant names - --> $DIR/offset-of-tuple.rs:8:27 + --> $DIR/offset-of-tuple.rs:9:27 | LL | offset_of!((u8, u8), 1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:9:29 + --> $DIR/offset-of-tuple.rs:10:29 | LL | offset_of!((u8, u8), 1 .); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:21:34 + --> $DIR/offset-of-tuple.rs:22:34 | LL | offset_of!(ComplexTup, 0.0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:22:35 + --> $DIR/offset-of-tuple.rs:23:35 | LL | offset_of!(ComplexTup, 0 .0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:23:36 + --> $DIR/offset-of-tuple.rs:24:36 | LL | offset_of!(ComplexTup, 0 . 0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:24:35 + --> $DIR/offset-of-tuple.rs:25:35 | LL | offset_of!(ComplexTup, 0. 0.1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:25:35 + --> $DIR/offset-of-tuple.rs:26:35 | LL | offset_of!(ComplexTup, 0.0 .1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:26:36 + --> $DIR/offset-of-tuple.rs:27:36 | LL | offset_of!(ComplexTup, 0.0 . 1.); | ^ error: unexpected token: `)` - --> $DIR/offset-of-tuple.rs:27:35 + --> $DIR/offset-of-tuple.rs:28:35 | LL | offset_of!(ComplexTup, 0.0. 1.); | ^ diff --git a/tests/ui/parser/builtin-syntax.rs b/tests/ui/parser/builtin-syntax.rs deleted file mode 100644 index 897dab8ec50ae..0000000000000 --- a/tests/ui/parser/builtin-syntax.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(builtin_syntax)] - -fn main() { - builtin # foobar(); //~ ERROR unknown `builtin #` construct -} - -fn not_identifier() { - builtin # {}(); //~ ERROR expected identifier after -} diff --git a/tests/ui/parser/builtin-syntax.stderr b/tests/ui/parser/builtin-syntax.stderr deleted file mode 100644 index ee3764a62216a..0000000000000 --- a/tests/ui/parser/builtin-syntax.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unknown `builtin #` construct `foobar` - --> $DIR/builtin-syntax.rs:4:5 - | -LL | builtin # foobar(); - | ^^^^^^^^^^^^^^^^ - -error: expected identifier after `builtin #` - --> $DIR/builtin-syntax.rs:8:15 - | -LL | builtin # {}(); - | ^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/suggestions/if-then-neeing-semi.stderr b/tests/ui/suggestions/if-then-neeing-semi.stderr index 0556d6c50b1ce..105e2756fb1db 100644 --- a/tests/ui/suggestions/if-then-neeing-semi.stderr +++ b/tests/ui/suggestions/if-then-neeing-semi.stderr @@ -52,12 +52,10 @@ help: consider `await`ing on the `Future` | LL | async_dummy2().await | ++++++ -help: consider removing this semicolon and boxing the expressions +help: consider removing this semicolon | -LL ~ Box::new(async_dummy()) -LL | -LL | } else { -LL ~ Box::new(async_dummy2()) +LL - async_dummy(); +LL + async_dummy() | error[E0308]: `if` and `else` have incompatible types diff --git a/tests/ui/suggestions/match-prev-arm-needing-semi.stderr b/tests/ui/suggestions/match-prev-arm-needing-semi.stderr index f70f6a1e1570b..c468433fd4421 100644 --- a/tests/ui/suggestions/match-prev-arm-needing-semi.stderr +++ b/tests/ui/suggestions/match-prev-arm-needing-semi.stderr @@ -52,12 +52,10 @@ help: consider `await`ing on the `Future` | LL | false => async_dummy2().await, | ++++++ -help: consider removing this semicolon and boxing the expressions +help: consider removing this semicolon | -LL ~ Box::new(async_dummy()) -LL | -LL | } -LL ~ false => Box::new(async_dummy2()), +LL - async_dummy(); +LL + async_dummy() | error[E0308]: `match` arms have incompatible types diff --git a/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr index 03249bd39a8c7..196eafa5bba68 100644 --- a/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr +++ b/tests/ui/suggestions/trait-with-missing-associated-type-restriction.stderr @@ -11,6 +11,10 @@ help: a method is available that returns `>::A` | LL | fn func(&self) -> Self::A; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` +help: consider returning the local binding `self` + | +LL | fn funq(&self) -> Self::A { self } + | ++++ error[E0308]: mismatched types --> $DIR/trait-with-missing-associated-type-restriction.rs:14:9 diff --git a/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr b/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr index 0ad8e3444600b..972a42d0f6621 100644 --- a/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr +++ b/tests/ui/traits/next-solver/normalization-shadowing/is-global-norm-concrete-alias-to-generic.current.stderr @@ -13,6 +13,10 @@ LL | x = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html = note: the associated type `<(*const T,) as Id>::This` is defined as `(*const T,)` in the implementation, but the where-bound `(*const T,)` shadows this definition see issue #152409 for more information +help: use a trailing comma to create a tuple with one element + | +LL | (x,) + | + ++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr new file mode 100644 index 0000000000000..fe8ef6aff748d --- /dev/null +++ b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.next.stderr @@ -0,0 +1,16 @@ +error[E0271]: type mismatch resolving `::AtLifetime<'static> == ExistentialLifetime<_>` + --> $DIR/rigid-alias-in-same-type-modulo-infer.rs:16:9 + | +LL | ExistentialLifetime(ExistentialLifetime(())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `ExistentialLifetime<_>`, found associated type + | + = note: expected struct `ExistentialLifetime<_>` + found associated type `::AtLifetime<'static>` +help: consider constraining the associated type `::AtLifetime<'static>` to `ExistentialLifetime<_>` + | +LL | impl = ExistentialLifetime<_>>> ExistentialLifetime { + | ++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr new file mode 100644 index 0000000000000..fe8ef6aff748d --- /dev/null +++ b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.old.stderr @@ -0,0 +1,16 @@ +error[E0271]: type mismatch resolving `::AtLifetime<'static> == ExistentialLifetime<_>` + --> $DIR/rigid-alias-in-same-type-modulo-infer.rs:16:9 + | +LL | ExistentialLifetime(ExistentialLifetime(())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `ExistentialLifetime<_>`, found associated type + | + = note: expected struct `ExistentialLifetime<_>` + found associated type `::AtLifetime<'static>` +help: consider constraining the associated type `::AtLifetime<'static>` to `ExistentialLifetime<_>` + | +LL | impl = ExistentialLifetime<_>>> ExistentialLifetime { + | ++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs new file mode 100644 index 0000000000000..c083234411fe8 --- /dev/null +++ b/tests/ui/traits/next-solver/rigid-alias-in-same-type-modulo-infer.rs @@ -0,0 +1,21 @@ +//! Regression test for . +// Avoids ICE on SameTypeModuloInfer assertion rigidity of two types. +// +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait HasLifetime { + type AtLifetime<'a>; +} + +pub struct ExistentialLifetime(S::AtLifetime<'static>); + +impl ExistentialLifetime { + fn new() -> ExistentialLifetime { + ExistentialLifetime(ExistentialLifetime(())) + //~^ ERROR: type mismatch resolving `::AtLifetime<'static> == ExistentialLifetime<_>` [E0271] + } +} + +fn main() {} diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 7eca271aeda13..3551d40dffbfc 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -10,12 +10,13 @@ // errors that only occur once we get past the AST. #![feature(auto_traits)] -#![feature(builtin_syntax)] +#![feature(internal_syntax)] #![feature(const_trait_impl)] #![feature(coroutines)] #![feature(decl_macro)] #![feature(deref_patterns)] #![feature(explicit_tail_calls)] +#![feature(forced_keywords)] #![feature(gen_blocks)] #![feature(more_qualified_paths)] #![feature(never_patterns)] @@ -131,7 +132,7 @@ mod expressions { fn expr_cast() { let expr; expr as T; expr as T; } /// ExprKind::Type - fn expr_type() { let expr; builtin # type_ascribe(expr, T); } + fn expr_type() { let expr; k#type_ascribe(expr, T); } /// ExprKind::Let fn expr_let() { @@ -315,7 +316,7 @@ mod expressions { - const { builtin # offset_of(T, field) }; + const { k#offset_of(T, field) }; } /// ExprKind::MacCall fn expr_mac_call() { "..."; "..."; "..."; } diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr index 5ca4b080a95e5..276bc5b5d2573 100644 --- a/tests/ui/unpretty/exhaustive.hir.stderr +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -1,17 +1,17 @@ error[E0697]: closures cannot be static - --> $DIR/exhaustive.rs:209:9 + --> $DIR/exhaustive.rs:210:9 | LL | static || value; | ^^^^^^^^^ error[E0697]: closures cannot be static - --> $DIR/exhaustive.rs:210:9 + --> $DIR/exhaustive.rs:211:9 | LL | static move || value; | ^^^^^^^^^^^^^^ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/exhaustive.rs:239:13 + --> $DIR/exhaustive.rs:240:13 | LL | fn expr_await() { | --------------- this is not `async` @@ -20,19 +20,19 @@ LL | fut.await; | ^^^^^ only allowed inside `async` functions and blocks error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/exhaustive.rs:290:9 + --> $DIR/exhaustive.rs:291:9 | LL | _; | ^ `_` not allowed here error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:300:9 + --> $DIR/exhaustive.rs:301:9 | LL | x::(); | ^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:301:9 + --> $DIR/exhaustive.rs:302:9 | LL | x::(T, T) -> T; | ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses @@ -44,31 +44,31 @@ LL + x:: -> T; | error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:302:9 + --> $DIR/exhaustive.rs:303:9 | LL | crate::() -> ()::expressions::() -> ()::expr_path; | ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:302:26 + --> $DIR/exhaustive.rs:303:26 | LL | crate::() -> ()::expressions::() -> ()::expr_path; | ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:305:9 + --> $DIR/exhaustive.rs:306:9 | LL | core::()::marker::()::PhantomData; | ^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:305:19 + --> $DIR/exhaustive.rs:306:19 | LL | core::()::marker::()::PhantomData; | ^^^^^^^^^^ only `Fn` traits may use parentheses error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks - --> $DIR/exhaustive.rs:392:9 + --> $DIR/exhaustive.rs:393:9 | LL | yield; | ^^^^^ @@ -79,7 +79,7 @@ LL | #[coroutine] fn expr_yield() { | ++++++++++++ error[E0703]: invalid ABI: found `C++` - --> $DIR/exhaustive.rs:472:23 + --> $DIR/exhaustive.rs:473:23 | LL | unsafe extern "C++" {} | ^^^^^ invalid ABI @@ -87,7 +87,7 @@ LL | unsafe extern "C++" {} = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: `..` patterns are not allowed here - --> $DIR/exhaustive.rs:674:13 + --> $DIR/exhaustive.rs:675:13 | LL | let ..; | ^^ @@ -95,13 +95,13 @@ LL | let ..; = note: only allowed in tuple, tuple struct, and slice patterns error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:789:16 + --> $DIR/exhaustive.rs:790:16 | LL | let _: T() -> !; | ^^^^^^^^ only `Fn` traits may use parentheses error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:803:16 + --> $DIR/exhaustive.rs:804:16 | LL | let _: impl Send; | ^^^^^^^^^ @@ -112,7 +112,7 @@ LL | let _: impl Send; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:804:16 + --> $DIR/exhaustive.rs:805:16 | LL | let _: impl Send + 'static; | ^^^^^^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL | let _: impl Send + 'static; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:805:16 + --> $DIR/exhaustive.rs:806:16 | LL | let _: impl 'static + Send; | ^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL | let _: impl 'static + Send; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:806:16 + --> $DIR/exhaustive.rs:807:16 | LL | let _: impl ?Sized; | ^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | let _: impl ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:807:16 + --> $DIR/exhaustive.rs:808:16 | LL | let _: impl [const] Clone; | ^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL | let _: impl [const] Clone; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:808:16 + --> $DIR/exhaustive.rs:809:16 | LL | let _: impl for<'a> Send; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index b1c956c2fe9f1..6af4d3b5b81de 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -1,8 +1,9 @@ -#![attr = Feature([auto_traits#0, builtin_syntax#0, const_trait_impl#0, +#![attr = Feature([auto_traits#0, internal_syntax#0, const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0, explicit_tail_calls#0, -gen_blocks#0, more_qualified_paths#0, never_patterns#0, pattern_types#0, -pattern_type_macro#0, prelude_import#0, specialization#0, trace_macros#0, -trait_alias#0, try_blocks#0, try_blocks_heterogeneous#0, yeet_expr#0])] +forced_keywords#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0, +pattern_types#0, pattern_type_macro#0, prelude_import#0, specialization#0, +trace_macros#0, trait_alias#0, try_blocks#0, try_blocks_heterogeneous#0, +yeet_expr#0])] #![attr = LintCheck([LintCheck {lint_name: LintName { tool: None, name: "incomplete_features" }, kind: Allow}, LintCheck {lint_name: LintName { tool: None, name: "unused_attributes" }, diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs index 03ef63874ac0a..15f684fc3dd72 100644 --- a/tests/ui/unpretty/exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -9,12 +9,13 @@ // errors that only occur once we get past the AST. #![feature(auto_traits)] -#![feature(builtin_syntax)] +#![feature(internal_syntax)] #![feature(const_trait_impl)] #![feature(coroutines)] #![feature(decl_macro)] #![feature(deref_patterns)] #![feature(explicit_tail_calls)] +#![feature(forced_keywords)] #![feature(gen_blocks)] #![feature(more_qualified_paths)] #![feature(never_patterns)] @@ -144,7 +145,7 @@ mod expressions { /// ExprKind::Type fn expr_type() { let expr; - builtin # type_ascribe(expr, T); + k#type_ascribe(expr, T); } /// ExprKind::Let