From 6d2ba95d0099f1a656da44c7f868be0074e5b5e1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 14 May 2023 19:10:52 +0200 Subject: [PATCH 01/11] suggest `Option::as_deref(_mut)` --- .../src/traits/error_reporting/suggestions.rs | 105 ++++++++++++++++-- .../suggest-option-asderef-unfixable.rs | 40 +++++++ .../suggest-option-asderef-unfixable.stderr | 96 ++++++++++++++++ .../suggest-option-asderef.fixed | 30 +++++ .../suggest-option-asderef.rs | 30 +++++ .../suggest-option-asderef.stderr | 63 +++++++++++ 6 files changed, 355 insertions(+), 9 deletions(-) create mode 100644 tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs create mode 100644 tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr create mode 100644 tests/ui/mismatched_types/suggest-option-asderef.fixed create mode 100644 tests/ui/mismatched_types/suggest-option-asderef.rs create mode 100644 tests/ui/mismatched_types/suggest-option-asderef.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 49b309abcda..9f2740a3898 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, Style, + ErrorGuaranteed, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -27,6 +27,7 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime}; use rustc_middle::hir::map; +use rustc_middle::query::Key; use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, @@ -357,6 +358,15 @@ pub trait TypeErrCtxtExt<'tcx> { err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); + + fn suggest_option_method_if_applicable( + &self, + failed_pred: ty::Predicate<'tcx>, + param_env: ty::ParamEnv<'tcx>, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + ); + fn note_function_argument_obligation( &self, body_id: LocalDefId, @@ -3660,15 +3670,92 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.replace_span_with(path.ident.span, true); } } - if let Some(Node::Expr(hir::Expr { - kind: - hir::ExprKind::Call(hir::Expr { span, .. }, _) - | hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..), - .. - })) = hir.find(call_hir_id) + + if let Some(Node::Expr(expr)) = hir.find(call_hir_id) { + if let hir::ExprKind::Call(hir::Expr { span, .. }, _) + | hir::ExprKind::MethodCall( + hir::PathSegment { ident: Ident { span, .. }, .. }, + .., + ) = expr.kind + { + if Some(*span) != err.span.primary_span() { + err.span_label(*span, "required by a bound introduced by this call"); + } + } + + if let hir::ExprKind::MethodCall(_, expr, ..) = expr.kind { + self.suggest_option_method_if_applicable(failed_pred, param_env, err, expr); + } + } + } + + fn suggest_option_method_if_applicable( + &self, + failed_pred: ty::Predicate<'tcx>, + param_env: ty::ParamEnv<'tcx>, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + ) { + let tcx = self.tcx; + let infcx = self.infcx; + let Some(typeck_results) = self.typeck_results.as_ref() else { return }; + + // Make sure we're dealing with the `Option` type. + let Some(ty_adt_did) = typeck_results.expr_ty_adjusted(expr).ty_adt_id() else { return }; + if !tcx.is_diagnostic_item(sym::Option, ty_adt_did) { + return; + } + + // Given the predicate `fn(&T): FnOnce<(U,)>`, extract `fn(&T)` and `(U,)`, + // then suggest `Option::as_deref(_mut)` if `U` can deref to `T` + if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { trait_ref, .. })) + = failed_pred.kind().skip_binder() + && tcx.is_fn_trait(trait_ref.def_id) + && let [self_ty, found_ty] = trait_ref.substs.as_slice() + && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn()) + && let fn_sig @ ty::FnSig { + abi: abi::Abi::Rust, + c_variadic: false, + unsafety: hir::Unsafety::Normal, + .. + } = fn_ty.fn_sig(tcx).skip_binder() + + // Extract first param of fn sig with peeled refs, e.g. `fn(&T)` -> `T` + && let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind()) + && !target_ty.has_escaping_bound_vars() + + // Extract first tuple element out of fn trait, e.g. `FnOnce<(U,)>` -> `U` + && let Some(ty::Tuple(tys)) = found_ty.as_type().map(Ty::kind) + && let &[found_ty] = tys.as_slice() + && !found_ty.has_escaping_bound_vars() + + // Extract `::Target` assoc type and check that it is `T` + && let Some(deref_target_did) = tcx.lang_items().deref_target() + && let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)])) + && let Ok(deref_target) = tcx.try_normalize_erasing_regions(param_env, projection) + && deref_target == target_ty { - if Some(*span) != err.span.primary_span() { - err.span_label(*span, "required by a bound introduced by this call"); + let help = if let hir::Mutability::Mut = needs_mut + && let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait() + && infcx + .type_implements_trait(deref_mut_did, iter::once(found_ty), param_env) + .must_apply_modulo_regions() + { + Some(("call `Option::as_deref_mut()` first", ".as_deref_mut()")) + } else if let hir::Mutability::Not = needs_mut { + Some(("call `Option::as_deref()` first", ".as_deref()")) + } else { + None + }; + + if let Some((msg, sugg)) = help { + err.span_suggestion_with_style( + expr.span.shrink_to_hi(), + msg, + sugg, + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways + ); } } } diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs new file mode 100644 index 00000000000..cc9ba5514fe --- /dev/null +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs @@ -0,0 +1,40 @@ +fn produces_string() -> Option { + Some("my cool string".to_owned()) +} + +fn takes_str_but_too_many_refs(_: &&str) -> Option<()> { + Some(()) +} + +fn no_args() -> Option<()> { + Some(()) +} + +fn generic_ref(_: &T) -> Option<()> { + Some(()) +} + +extern "C" fn takes_str_but_wrong_abi(_: &str) -> Option<()> { + Some(()) +} + +unsafe fn takes_str_but_unsafe(_: &str) -> Option<()> { + Some(()) +} + +struct TypeWithoutDeref; + +fn main() { + let _ = produces_string().and_then(takes_str_but_too_many_refs); + //~^ ERROR type mismatch in function arguments + let _ = produces_string().and_then(takes_str_but_wrong_abi); + //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` + let _ = produces_string().and_then(takes_str_but_unsafe); + //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` + let _ = produces_string().and_then(no_args); + //~^ ERROR function is expected to take 1 argument, but it takes 0 arguments + let _ = produces_string().and_then(generic_ref); + //~^ ERROR type mismatch in function arguments + let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); + //~^ ERROR type mismatch in function arguments +} diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr new file mode 100644 index 00000000000..079909eb48d --- /dev/null +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr @@ -0,0 +1,96 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/suggest-option-asderef-unfixable.rs:28:40 + | +LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> { + | ------------------------------------------------------ found signature defined here +... +LL | let _ = produces_string().and_then(takes_str_but_too_many_refs); + | -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(String) -> _` + found function signature `for<'a, 'b> fn(&'a &'b str) -> _` +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` + --> $DIR/suggest-option-asderef-unfixable.rs:30:40 + | +LL | let _ = produces_string().and_then(takes_str_but_wrong_abi); + | -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<(String,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` + --> $DIR/suggest-option-asderef-unfixable.rs:32:40 + | +LL | let _ = produces_string().and_then(takes_str_but_unsafe); + | -------- ^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `FnOnce<(String,)>` is not implemented for fn item `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` + = note: unsafe function cannot be called generically without an unsafe block +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0593]: function is expected to take 1 argument, but it takes 0 arguments + --> $DIR/suggest-option-asderef-unfixable.rs:34:40 + | +LL | fn no_args() -> Option<()> { + | -------------------------- takes 0 arguments +... +LL | let _ = produces_string().and_then(no_args); + | -------- ^^^^^^^ expected function that takes 1 argument + | | + | required by a bound introduced by this call + | +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0631]: type mismatch in function arguments + --> $DIR/suggest-option-asderef-unfixable.rs:36:40 + | +LL | fn generic_ref(_: &T) -> Option<()> { + | -------------------------------------- found signature defined here +... +LL | let _ = produces_string().and_then(generic_ref); + | -------- ^^^^^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(String) -> _` + found function signature `for<'a> fn(&'a _) -> _` +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: do not borrow the argument + | +LL - fn generic_ref(_: &T) -> Option<()> { +LL + fn generic_ref(_: T) -> Option<()> { + | + +error[E0631]: type mismatch in function arguments + --> $DIR/suggest-option-asderef-unfixable.rs:38:45 + | +LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> { + | ------------------------------------------------------ found signature defined here +... +LL | let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); + | -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(TypeWithoutDeref) -> _` + found function signature `for<'a, 'b> fn(&'a &'b str) -> _` +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0593, E0631. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/suggest-option-asderef.fixed b/tests/ui/mismatched_types/suggest-option-asderef.fixed new file mode 100644 index 00000000000..08805999341 --- /dev/null +++ b/tests/ui/mismatched_types/suggest-option-asderef.fixed @@ -0,0 +1,30 @@ +// run-rustfix + +fn produces_string() -> Option { + Some("my cool string".to_owned()) +} + +fn takes_str(_: &str) -> Option<()> { + Some(()) +} + +fn takes_str_mut(_: &mut str) -> Option<()> { + Some(()) +} + +fn generic(_: T) -> Option<()> { + Some(()) +} + +fn main() { + let _: Option<()> = produces_string().as_deref().and_then(takes_str); + //~^ ERROR type mismatch in function arguments + //~| HELP call `Option::as_deref()` first + let _: Option> = produces_string().as_deref().map(takes_str); + //~^ ERROR type mismatch in function arguments + //~| HELP call `Option::as_deref()` first + let _: Option> = produces_string().as_deref_mut().map(takes_str_mut); + //~^ ERROR type mismatch in function arguments + //~| HELP call `Option::as_deref_mut()` first + let _ = produces_string().and_then(generic); +} diff --git a/tests/ui/mismatched_types/suggest-option-asderef.rs b/tests/ui/mismatched_types/suggest-option-asderef.rs new file mode 100644 index 00000000000..3cfb2ffa828 --- /dev/null +++ b/tests/ui/mismatched_types/suggest-option-asderef.rs @@ -0,0 +1,30 @@ +// run-rustfix + +fn produces_string() -> Option { + Some("my cool string".to_owned()) +} + +fn takes_str(_: &str) -> Option<()> { + Some(()) +} + +fn takes_str_mut(_: &mut str) -> Option<()> { + Some(()) +} + +fn generic(_: T) -> Option<()> { + Some(()) +} + +fn main() { + let _: Option<()> = produces_string().and_then(takes_str); + //~^ ERROR type mismatch in function arguments + //~| HELP call `Option::as_deref()` first + let _: Option> = produces_string().map(takes_str); + //~^ ERROR type mismatch in function arguments + //~| HELP call `Option::as_deref()` first + let _: Option> = produces_string().map(takes_str_mut); + //~^ ERROR type mismatch in function arguments + //~| HELP call `Option::as_deref_mut()` first + let _ = produces_string().and_then(generic); +} diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr new file mode 100644 index 00000000000..46da19d2bf4 --- /dev/null +++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr @@ -0,0 +1,63 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/suggest-option-asderef.rs:20:52 + | +LL | fn takes_str(_: &str) -> Option<()> { + | ----------------------------------- found signature defined here +... +LL | let _: Option<()> = produces_string().and_then(takes_str); + | -------- ^^^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(String) -> _` + found function signature `for<'a> fn(&'a str) -> _` +note: required by a bound in `Option::::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: call `Option::as_deref()` first + | +LL | let _: Option<()> = produces_string().as_deref().and_then(takes_str); + | +++++++++++ + +error[E0631]: type mismatch in function arguments + --> $DIR/suggest-option-asderef.rs:23:55 + | +LL | fn takes_str(_: &str) -> Option<()> { + | ----------------------------------- found signature defined here +... +LL | let _: Option> = produces_string().map(takes_str); + | --- ^^^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(String) -> _` + found function signature `for<'a> fn(&'a str) -> _` +note: required by a bound in `Option::::map` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: call `Option::as_deref()` first + | +LL | let _: Option> = produces_string().as_deref().map(takes_str); + | +++++++++++ + +error[E0631]: type mismatch in function arguments + --> $DIR/suggest-option-asderef.rs:26:55 + | +LL | fn takes_str_mut(_: &mut str) -> Option<()> { + | ------------------------------------------- found signature defined here +... +LL | let _: Option> = produces_string().map(takes_str_mut); + | --- ^^^^^^^^^^^^^ expected due to this + | | + | required by a bound introduced by this call + | + = note: expected function signature `fn(String) -> _` + found function signature `for<'a> fn(&'a mut str) -> _` +note: required by a bound in `Option::::map` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: call `Option::as_deref_mut()` first + | +LL | let _: Option> = produces_string().as_deref_mut().map(takes_str_mut); + | +++++++++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0631`. From 440912b74f5ac063d8993741120a519bed3882f2 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 17 May 2023 17:29:02 -0400 Subject: [PATCH 02/11] Option::map_or_else: Show an example of integrating with Result Moving this from https://github.com/rust-lang/libs-team/issues/59 where an API addition was rejected. But I think it's valuable to add this example to the documentation at least. --- library/core/src/option.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ec1ef3cf43d..b93b40e3003 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1138,7 +1138,7 @@ impl Option { /// Computes a default function result (if none), or /// applies a different function to the contained value (if any). /// - /// # Examples + /// # Basic examples /// /// ``` /// let k = 21; @@ -1149,6 +1149,25 @@ impl Option { /// let x: Option<&str> = None; /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); /// ``` + /// + /// # Handling a Result-based fallback + /// + /// A somewhat common occurrence when dealing with optional values + /// in combination with [`Result`] is the case where one wants to invoke + /// a fallible fallback if the option is not present. This example + /// parses a command line argument (if present), or the contents of a file to + /// an integer. However, unlike accessing the command line argument, reading + /// the file is fallible, so it must be wrapped with `Ok`. + /// + /// ```no_run + /// # fn main() -> Result<(), Box> { + /// let v: u64 = std::env::args() + /// .nth(1) + /// .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)? + /// .parse()?; + /// # Ok(()) + /// # } + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn map_or_else(self, default: D, f: F) -> U From 5fdeae610db96d048090b1efaf6b7a2f54aeda12 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 23 May 2023 15:11:17 +0200 Subject: [PATCH 03/11] codegen: allow extra attributes to functions when panic=abort When compiling with panic=abort (or using a target that doesn't have unwinding support), the compiler adds the "nounwind" attribute to functions. This results in a different LLVM IR, which results in a #NNN added after the function name: tail call void @bar() #13, !dbg !467 attributes #13 = { nounwind } ...instead of: tail call void @bar(), !dbg !467 This commit changes the matchers to swallow the #NNN, as it's not needed for these specific tests. --- tests/codegen/call-metadata.rs | 2 +- tests/codegen/debug-column.rs | 4 ++-- tests/codegen/mir-inlined-line-numbers.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/codegen/call-metadata.rs b/tests/codegen/call-metadata.rs index 1c30c08d3b2..07cc0c96371 100644 --- a/tests/codegen/call-metadata.rs +++ b/tests/codegen/call-metadata.rs @@ -6,7 +6,7 @@ #![crate_type = "lib"] pub fn test() { - // CHECK: call noundef i8 @some_true(), !range [[R0:![0-9]+]] + // CHECK: call noundef i8 @some_true(){{( #[0-9]+)?}}, !range [[R0:![0-9]+]] // CHECK: [[R0]] = !{i8 0, i8 3} some_true(); } diff --git a/tests/codegen/debug-column.rs b/tests/codegen/debug-column.rs index e61642b8e1b..f3b19a2eb2f 100644 --- a/tests/codegen/debug-column.rs +++ b/tests/codegen/debug-column.rs @@ -6,11 +6,11 @@ fn main() { unsafe { // Column numbers are 1-based. Regression test for #65437. - // CHECK: call void @giraffe(), !dbg [[A:!.*]] + // CHECK: call void @giraffe(){{( #[0-9]+)?}}, !dbg [[A:!.*]] giraffe(); // Column numbers use byte offests. Regression test for #67360 - // CHECK: call void @turtle(), !dbg [[B:!.*]] + // CHECK: call void @turtle(){{( #[0-9]+)?}}, !dbg [[B:!.*]] /* ż */ turtle(); // CHECK: [[A]] = !DILocation(line: 10, column: 9, diff --git a/tests/codegen/mir-inlined-line-numbers.rs b/tests/codegen/mir-inlined-line-numbers.rs index 19d83f0eee7..d13527b9521 100644 --- a/tests/codegen/mir-inlined-line-numbers.rs +++ b/tests/codegen/mir-inlined-line-numbers.rs @@ -19,7 +19,7 @@ pub fn example() { } // CHECK-LABEL: @example -// CHECK: tail call void @bar(), !dbg [[DBG_ID:![0-9]+]] +// CHECK: tail call void @bar(){{( #[0-9]+)?}}, !dbg [[DBG_ID:![0-9]+]] // CHECK: [[DBG_ID]] = !DILocation(line: 7, // CHECK-SAME: inlinedAt: [[INLINE_ID:![0-9]+]]) // CHECK: [[INLINE_ID]] = !DILocation(line: 18, From dc1ed9ddd7d15dfe75453b68bc1da8ae32dbe1f7 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 23 May 2023 15:26:31 +0200 Subject: [PATCH 04/11] codegen: allow the dso_local attribute The attribute is injected into most items when static relocation is enabled in a target. --- tests/codegen/box-maybe-uninit-llvm14.rs | 2 +- tests/codegen/box-maybe-uninit.rs | 2 +- tests/codegen/external-no-mangle-statics.rs | 32 ++++++++++----------- tests/codegen/issues/issue-86106.rs | 4 +-- tests/codegen/link_section.rs | 8 +++--- tests/codegen/naked-noinline.rs | 4 +-- tests/codegen/ptr-read-metadata.rs | 16 +++++------ tests/codegen/tuple-layout-opt.rs | 12 ++++---- tests/codegen/union-abi.rs | 20 ++++++------- 9 files changed, 50 insertions(+), 50 deletions(-) diff --git a/tests/codegen/box-maybe-uninit-llvm14.rs b/tests/codegen/box-maybe-uninit-llvm14.rs index b0c88f76c43..c9f88fb3fe4 100644 --- a/tests/codegen/box-maybe-uninit-llvm14.rs +++ b/tests/codegen/box-maybe-uninit-llvm14.rs @@ -31,4 +31,4 @@ pub fn box_uninitialized2() -> Box> { // Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc // from the CHECK-NOT above. We don't check the attributes here because we can't rely // on all of them being set until LLVM 15. -// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef) +// CHECK: declare {{(dso_local )?}}noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef) diff --git a/tests/codegen/box-maybe-uninit.rs b/tests/codegen/box-maybe-uninit.rs index 2f88966996a..9f079e99b9c 100644 --- a/tests/codegen/box-maybe-uninit.rs +++ b/tests/codegen/box-maybe-uninit.rs @@ -28,6 +28,6 @@ pub fn box_uninitialized2() -> Box> { // Hide the `allocalign` attribute in the declaration of __rust_alloc // from the CHECK-NOT above, and also verify the attributes got set reasonably. -// CHECK: declare noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] +// CHECK: declare {{(dso_local )?}}noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen/external-no-mangle-statics.rs b/tests/codegen/external-no-mangle-statics.rs index c6ecb7aa96a..48023a2a901 100644 --- a/tests/codegen/external-no-mangle-statics.rs +++ b/tests/codegen/external-no-mangle-statics.rs @@ -6,72 +6,72 @@ // `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their // definitions -// CHECK: @A = local_unnamed_addr constant +// CHECK: @A = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static A: u8 = 0; -// CHECK: @B = local_unnamed_addr global +// CHECK: @B = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut B: u8 = 0; -// CHECK: @C = local_unnamed_addr constant +// CHECK: @C = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static C: u8 = 0; -// CHECK: @D = local_unnamed_addr global +// CHECK: @D = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut D: u8 = 0; mod private { - // CHECK: @E = local_unnamed_addr constant + // CHECK: @E = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static E: u8 = 0; - // CHECK: @F = local_unnamed_addr global + // CHECK: @F = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut F: u8 = 0; - // CHECK: @G = local_unnamed_addr constant + // CHECK: @G = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static G: u8 = 0; - // CHECK: @H = local_unnamed_addr global + // CHECK: @H = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut H: u8 = 0; } const HIDDEN: () = { - // CHECK: @I = local_unnamed_addr constant + // CHECK: @I = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static I: u8 = 0; - // CHECK: @J = local_unnamed_addr global + // CHECK: @J = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut J: u8 = 0; - // CHECK: @K = local_unnamed_addr constant + // CHECK: @K = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static K: u8 = 0; - // CHECK: @L = local_unnamed_addr global + // CHECK: @L = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut L: u8 = 0; }; fn x() { - // CHECK: @M = local_unnamed_addr constant + // CHECK: @M = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] static M: fn() = x; - // CHECK: @N = local_unnamed_addr global + // CHECK: @N = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] static mut N: u8 = 0; - // CHECK: @O = local_unnamed_addr constant + // CHECK: @O = {{(dso_local )?}}local_unnamed_addr constant #[no_mangle] pub static O: u8 = 0; - // CHECK: @P = local_unnamed_addr global + // CHECK: @P = {{(dso_local )?}}local_unnamed_addr global #[no_mangle] pub static mut P: u8 = 0; } diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs index c0be7fab2f3..be5034dcfbd 100644 --- a/tests/codegen/issues/issue-86106.rs +++ b/tests/codegen/issues/issue-86106.rs @@ -7,7 +7,7 @@ #![crate_type = "lib"] -// CHECK-LABEL: define void @string_new +// CHECK-LABEL: define {{(dso_local )?}}void @string_new #[no_mangle] pub fn string_new() -> String { // CHECK: store ptr inttoptr @@ -17,7 +17,7 @@ pub fn string_new() -> String { String::new() } -// CHECK-LABEL: define void @empty_to_string +// CHECK-LABEL: define {{(dso_local )?}}void @empty_to_string #[no_mangle] pub fn empty_to_string() -> String { // CHECK: store ptr inttoptr diff --git a/tests/codegen/link_section.rs b/tests/codegen/link_section.rs index 88b8692b0ac..2b26b604ad3 100644 --- a/tests/codegen/link_section.rs +++ b/tests/codegen/link_section.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" +// CHECK: @VAR1 = {{(dso_local )?}}constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] #[cfg(target_endian = "little")] @@ -19,17 +19,17 @@ pub enum E { B(f32) } -// CHECK: @VAR2 = constant {{.*}}, section ".test_two" +// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two" #[no_mangle] #[link_section = ".test_two"] pub static VAR2: E = E::A(666); -// CHECK: @VAR3 = constant {{.*}}, section ".test_three" +// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three" #[no_mangle] #[link_section = ".test_three"] pub static VAR3: E = E::B(1.); -// CHECK: define void @fn1() {{.*}} section ".test_four" { +// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" { #[no_mangle] #[link_section = ".test_four"] pub fn fn1() {} diff --git a/tests/codegen/naked-noinline.rs b/tests/codegen/naked-noinline.rs index c0ac69f4ed7..5cfb500c0ef 100644 --- a/tests/codegen/naked-noinline.rs +++ b/tests/codegen/naked-noinline.rs @@ -12,7 +12,7 @@ use std::arch::asm; pub unsafe extern "C" fn f() { // Check that f has naked and noinline attributes. // - // CHECK: define void @f() unnamed_addr [[ATTR:#[0-9]+]] + // CHECK: define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]] // CHECK-NEXT: start: // CHECK-NEXT: call void asm asm!("", options(noreturn)); @@ -22,7 +22,7 @@ pub unsafe extern "C" fn f() { pub unsafe fn g() { // Check that call to f is not inlined. // - // CHECK-LABEL: define void @g() + // CHECK-LABEL: define {{(dso_local )?}}void @g() // CHECK-NEXT: start: // CHECK-NEXT: call void @f() f(); diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs index e1e3272662c..73d1db6df27 100644 --- a/tests/codegen/ptr-read-metadata.rs +++ b/tests/codegen/ptr-read-metadata.rs @@ -9,7 +9,7 @@ use std::mem::MaybeUninit; -// CHECK-LABEL: define noundef i8 @copy_byte( +// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @copy_byte( #[no_mangle] pub unsafe fn copy_byte(p: *const u8) -> u8 { // CHECK-NOT: load @@ -19,7 +19,7 @@ pub unsafe fn copy_byte(p: *const u8) -> u8 { *p } -// CHECK-LABEL: define noundef i8 @read_byte( +// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte( #[no_mangle] pub unsafe fn read_byte(p: *const u8) -> u8 { // CHECK-NOT: load @@ -29,7 +29,7 @@ pub unsafe fn read_byte(p: *const u8) -> u8 { p.read() } -// CHECK-LABEL: define i8 @read_byte_maybe_uninit( +// CHECK-LABEL: define {{(dso_local )?}}i8 @read_byte_maybe_uninit( #[no_mangle] pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit { // CHECK-NOT: load @@ -39,7 +39,7 @@ pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit) -> u8 { // CHECK-NOT: load @@ -49,7 +49,7 @@ pub unsafe fn read_byte_assume_init(p: &MaybeUninit) -> u8 { p.assume_init_read() } -// CHECK-LABEL: define noundef i32 @copy_char( +// CHECK-LABEL: define {{(dso_local )?}}noundef i32 @copy_char( #[no_mangle] pub unsafe fn copy_char(p: *const char) -> char { // CHECK-NOT: load @@ -60,7 +60,7 @@ pub unsafe fn copy_char(p: *const char) -> char { *p } -// CHECK-LABEL: define noundef i32 @read_char( +// CHECK-LABEL: define {{(dso_local )?}}noundef i32 @read_char( #[no_mangle] pub unsafe fn read_char(p: *const char) -> char { // CHECK-NOT: load @@ -71,7 +71,7 @@ pub unsafe fn read_char(p: *const char) -> char { p.read() } -// CHECK-LABEL: define i32 @read_char_maybe_uninit( +// CHECK-LABEL: define {{(dso_local )?}}i32 @read_char_maybe_uninit( #[no_mangle] pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit { // CHECK-NOT: load @@ -82,7 +82,7 @@ pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit) -> MaybeUninit p.read() } -// CHECK-LABEL: define noundef i32 @read_char_assume_init( +// CHECK-LABEL: define {{(dso_local )?}}noundef i32 @read_char_assume_init( #[no_mangle] pub unsafe fn read_char_assume_init(p: &MaybeUninit) -> char { // CHECK-NOT: load diff --git a/tests/codegen/tuple-layout-opt.rs b/tests/codegen/tuple-layout-opt.rs index 35f76085145..309fe1d5ec9 100644 --- a/tests/codegen/tuple-layout-opt.rs +++ b/tests/codegen/tuple-layout-opt.rs @@ -6,31 +6,31 @@ #![crate_type="lib"] type ScalarZstLast = (u128, ()); -// CHECK: define i128 @test_ScalarZstLast(i128 %_1) +// CHECK: define {{(dso_local )?}}i128 @test_ScalarZstLast(i128 %_1) #[no_mangle] pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} } type ScalarZstFirst = ((), u128); -// CHECK: define i128 @test_ScalarZstFirst(i128 %_1) +// CHECK: define {{(dso_local )?}}i128 @test_ScalarZstFirst(i128 %_1) #[no_mangle] pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} } type ScalarPairZstLast = (u8, u128, ()); -// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) +// CHECK: define {{(dso_local )?}}{ i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) #[no_mangle] pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} } type ScalarPairZstFirst = ((), u8, u128); -// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) +// CHECK: define {{(dso_local )?}}{ i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) #[no_mangle] pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} } type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); -// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) +// CHECK: define {{(dso_local )?}}{ i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) #[no_mangle] pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} } type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); -// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) +// CHECK: define {{(dso_local )?}}{ i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) #[no_mangle] pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} } diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs index c18f2a49fc3..8481ca8ccfa 100644 --- a/tests/codegen/union-abi.rs +++ b/tests/codegen/union-abi.rs @@ -17,60 +17,60 @@ pub struct i64x4(i64, i64, i64, i64); #[derive(Copy, Clone)] pub union UnionI64x4{ a:(), b: i64x4 } -// CHECK: define void @test_UnionI64x4({{<4 x i64>\*|ptr}} {{.*}} %_1) +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4({{<4 x i64>\*|ptr}} {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4(_: UnionI64x4) { loop {} } pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } -// CHECK: define void @test_UnionI64x4_({{<4 x i64>\*|ptr}} {{.*}} %_1) +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_({{<4 x i64>\*|ptr}} {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} } pub union UnionI64x4I64{ a: i64x4, b: i64 } -// CHECK: define void @test_UnionI64x4I64({{%UnionI64x4I64\*|ptr}} {{.*}} %_1) +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64({{%UnionI64x4I64\*|ptr}} {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} } pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) } -// CHECK: define void @test_UnionI64x4Tuple({{%UnionI64x4Tuple\*|ptr}} {{.*}} %_1) +// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple({{%UnionI64x4Tuple\*|ptr}} {{.*}} %_1) #[no_mangle] pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} } pub union UnionF32{a:f32} -// CHECK: define float @test_UnionF32(float %_1) +// CHECK: define {{(dso_local )?}}float @test_UnionF32(float %_1) #[no_mangle] pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } pub union UnionF32F32{a:f32, b:f32} -// CHECK: define float @test_UnionF32F32(float %_1) +// CHECK: define {{(dso_local )?}}float @test_UnionF32F32(float %_1) #[no_mangle] pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } pub union UnionF32U32{a:f32, b:u32} -// CHECK: define i32 @test_UnionF32U32(i32{{( %0)?}}) +// CHECK: define {{(dso_local )?}}i32 @test_UnionF32U32(i32{{( %0)?}}) #[no_mangle] pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } pub union UnionU128{a:u128} -// CHECK: define i128 @test_UnionU128(i128 %_1) +// CHECK: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1) #[no_mangle] pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } #[repr(C)] pub union CUnionU128{a:u128} -// CHECK: define void @test_CUnionU128({{%CUnionU128\*|ptr}} {{.*}} %_1) +// CHECK: define {{(dso_local )?}}void @test_CUnionU128({{%CUnionU128\*|ptr}} {{.*}} %_1) #[no_mangle] pub fn test_CUnionU128(_: CUnionU128) { loop {} } pub union UnionBool { b:bool } -// CHECK: define noundef zeroext i1 @test_UnionBool(i8 %b) +// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b) #[no_mangle] pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b } } // CHECK: %0 = trunc i8 %b to i1 From 292bc548c882686f40886934f2055f3440a87eca Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 23 May 2023 15:27:05 +0200 Subject: [PATCH 05/11] codegen: do not require the uwtables attribute The attribute is not emitted on targets without unwinding tables. --- tests/codegen/box-maybe-uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen/box-maybe-uninit.rs b/tests/codegen/box-maybe-uninit.rs index 9f079e99b9c..5c08b5832ad 100644 --- a/tests/codegen/box-maybe-uninit.rs +++ b/tests/codegen/box-maybe-uninit.rs @@ -30,4 +30,4 @@ pub fn box_uninitialized2() -> Box> { // from the CHECK-NOT above, and also verify the attributes got set reasonably. // CHECK: declare {{(dso_local )?}}noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] -// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } +// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} } From 5f0b677b86204c4cd98cf51b33b7224340406719 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 23 May 2023 15:20:57 +0200 Subject: [PATCH 06/11] codegen: add needs-unwind to tests that require it --- tests/codegen/drop.rs | 1 + tests/codegen/personality_lifetimes.rs | 1 + tests/codegen/unwind-abis/c-unwind-abi.rs | 1 + tests/codegen/unwind-abis/cdecl-unwind-abi.rs | 1 + tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs | 1 + tests/codegen/unwind-abis/system-unwind-abi.rs | 1 + tests/codegen/unwind-extern-exports.rs | 1 + tests/codegen/unwind-extern-imports.rs | 1 + tests/codegen/vec-shrink-panik.rs | 1 + 9 files changed, 9 insertions(+) diff --git a/tests/codegen/drop.rs b/tests/codegen/drop.rs index 99402827158..3615ef47b53 100644 --- a/tests/codegen/drop.rs +++ b/tests/codegen/drop.rs @@ -1,4 +1,5 @@ // ignore-wasm32-bare compiled with panic=abort by default +// needs-unwind - this test verifies the amount of drop calls when unwinding is used // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/tests/codegen/personality_lifetimes.rs b/tests/codegen/personality_lifetimes.rs index 2104022f578..9ff7a9b3e88 100644 --- a/tests/codegen/personality_lifetimes.rs +++ b/tests/codegen/personality_lifetimes.rs @@ -1,5 +1,6 @@ // ignore-msvc // ignore-wasm32-bare compiled with panic=abort by default +// needs-unwind // compile-flags: -O -C no-prepopulate-passes diff --git a/tests/codegen/unwind-abis/c-unwind-abi.rs b/tests/codegen/unwind-abis/c-unwind-abi.rs index e258dbcacd2..fa5b6bad75c 100644 --- a/tests/codegen/unwind-abis/c-unwind-abi.rs +++ b/tests/codegen/unwind-abis/c-unwind-abi.rs @@ -1,4 +1,5 @@ // compile-flags: -C opt-level=0 +// needs-unwind // Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern // functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above diff --git a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs index 19a7228839a..64746d32175 100644 --- a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs +++ b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs @@ -1,4 +1,5 @@ // compile-flags: -C opt-level=0 +// needs-unwind // Test that `nounwind` attributes are correctly applied to exported `cdecl` and // `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We diff --git a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs index c1c5bbdda34..dc3911cd4eb 100644 --- a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs +++ b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs @@ -1,5 +1,6 @@ // compile-flags: -C opt-level=0 // ignore-wasm32-bare compiled with panic=abort by default +// needs-unwind #![crate_type = "lib"] diff --git a/tests/codegen/unwind-abis/system-unwind-abi.rs b/tests/codegen/unwind-abis/system-unwind-abi.rs index 2591c1d4814..f274a33b099 100644 --- a/tests/codegen/unwind-abis/system-unwind-abi.rs +++ b/tests/codegen/unwind-abis/system-unwind-abi.rs @@ -1,4 +1,5 @@ // compile-flags: -C opt-level=0 +// needs-unwind // Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind` // extern functions. `system-unwind` functions MUST NOT have this attribute. We disable diff --git a/tests/codegen/unwind-extern-exports.rs b/tests/codegen/unwind-extern-exports.rs index 6ac3c079f81..4e1e719d5cd 100644 --- a/tests/codegen/unwind-extern-exports.rs +++ b/tests/codegen/unwind-extern-exports.rs @@ -1,5 +1,6 @@ // compile-flags: -C opt-level=0 // ignore-wasm32-bare compiled with panic=abort by default +// needs-unwind #![crate_type = "lib"] #![feature(c_unwind)] diff --git a/tests/codegen/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs index e33e3e80521..260dcc628cc 100644 --- a/tests/codegen/unwind-extern-imports.rs +++ b/tests/codegen/unwind-extern-imports.rs @@ -1,5 +1,6 @@ // compile-flags: -C no-prepopulate-passes // ignore-wasm32-bare compiled with panic=abort by default +// needs-unwind #![crate_type = "lib"] #![feature(c_unwind)] diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index 88b7edff260..606d68ff3ab 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -5,6 +5,7 @@ // [new]min-llvm-version: 17 // compile-flags: -O // ignore-debug: the debug assertions get in the way +// needs-unwind #![crate_type = "lib"] #![feature(shrink_to)] From ec33e6414cc39a34d2c49f6efdf933ca21a0136c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 25 May 2023 23:32:07 +0000 Subject: [PATCH 07/11] bootstrap: Make `clean` respect `dry-run` --- src/bootstrap/clean.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 0d9fd56b038..c1d867a0bd1 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -85,6 +85,10 @@ clean_crate_tree! { } fn clean_default(build: &Build, all: bool) { + if build.config.dry_run() { + return; + } + rm_rf("tmp".as_ref()); if all { From 8458c6adb131345dbf0b48e23c8d220dc41c19fd Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 26 May 2023 12:08:58 -0500 Subject: [PATCH 08/11] Add other workspaces to `linkedProjects` in `rust_analyzer_settings.json` This makes go-to-definition, etc. work in cg_clif, cg_gcc, rust-analyzer, and src/tools/x. --- src/bootstrap/setup.rs | 1 + src/etc/rust_analyzer_settings.json | 9 ++++++++- src/tools/x/Cargo.lock | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 09f26862b4a..606a064bf6d 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -31,6 +31,7 @@ static SETTINGS_HASHES: &[&str] = &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", ]; static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json"); diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index dd01bfaa725..d9c4645f0b3 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -7,7 +7,14 @@ "check", "--json-output" ], - "rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"], + "rust-analyzer.linkedProjects": [ + "Cargo.toml", + "src/tools/x/Cargo.toml", + "src/bootstrap/Cargo.toml", + "src/tools/rust-analyzer/Cargo.toml", + "compiler/rustc_codegen_cranelift/Cargo.toml", + "compiler/rustc_codegen_gcc/Cargo.toml" + ], "rust-analyzer.rustfmt.overrideCommand": [ "./build/host/rustfmt/bin/rustfmt", "--edition=2021" diff --git a/src/tools/x/Cargo.lock b/src/tools/x/Cargo.lock index 723d6cb25ed..09e5c750749 100644 --- a/src/tools/x/Cargo.lock +++ b/src/tools/x/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "x" -version = "0.1.0" +version = "0.1.1" From 9f70efb31aa9345e07b547b3d4f63a1e08b53c49 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Jun 2023 16:37:51 +0000 Subject: [PATCH 09/11] only suppress coercion error if type is definitely unsized --- compiler/rustc_hir_typeck/src/coercion.rs | 30 ++++++++++++------- tests/ui/typeck/return-dyn-type-mismatch-2.rs | 11 +++++++ .../typeck/return-dyn-type-mismatch-2.stderr | 15 ++++++++++ tests/ui/typeck/return-dyn-type-mismatch.rs | 21 +++++++++++++ .../ui/typeck/return-dyn-type-mismatch.stderr | 15 ++++++++++ 5 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 tests/ui/typeck/return-dyn-type-mismatch-2.rs create mode 100644 tests/ui/typeck/return-dyn-type-mismatch-2.stderr create mode 100644 tests/ui/typeck/return-dyn-type-mismatch.rs create mode 100644 tests/ui/typeck/return-dyn-type-mismatch.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 905781ec8f5..ba49e0c4161 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1595,7 +1595,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { Some(blk_id), ); if !fcx.tcx.features().unsized_locals { - unsized_return = self.is_return_ty_unsized(fcx, blk_id); + unsized_return = self.is_return_ty_definitely_unsized(fcx); } if let Some(expression) = expression && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { @@ -1614,8 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { None, ); if !fcx.tcx.features().unsized_locals { - let id = fcx.tcx.hir().parent_id(id); - unsized_return = self.is_return_ty_unsized(fcx, id); + unsized_return = self.is_return_ty_definitely_unsized(fcx); } } _ => { @@ -1896,15 +1895,24 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.help("you could instead create a new `enum` with a variant for each returned type"); } - fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { - if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id) - && let hir::FnRetTy::Return(ty) = fn_decl.output - && let ty = fcx.astconv().ast_ty_to_ty( ty) - && let ty::Dynamic(..) = ty.kind() - { - return true; + /// Checks whether the return type is unsized via an obligation, which makes + /// sure we consider `dyn Trait: Sized` where clauses, which are trivially + /// false but technically valid for typeck. + fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool { + if let Some(sig) = fcx.body_fn_sig() { + !fcx.predicate_may_hold(&Obligation::new( + fcx.tcx, + ObligationCause::dummy(), + fcx.param_env, + ty::TraitRef::new( + fcx.tcx, + fcx.tcx.require_lang_item(hir::LangItem::Sized, None), + [sig.output()], + ), + )) + } else { + false } - false } pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> { diff --git a/tests/ui/typeck/return-dyn-type-mismatch-2.rs b/tests/ui/typeck/return-dyn-type-mismatch-2.rs new file mode 100644 index 00000000000..328f154dcbc --- /dev/null +++ b/tests/ui/typeck/return-dyn-type-mismatch-2.rs @@ -0,0 +1,11 @@ +trait Trait {} + +fn foo() -> dyn Trait +where + dyn Trait: Sized, // pesky sized predicate +{ + 42 + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/typeck/return-dyn-type-mismatch-2.stderr b/tests/ui/typeck/return-dyn-type-mismatch-2.stderr new file mode 100644 index 00000000000..9c368e83834 --- /dev/null +++ b/tests/ui/typeck/return-dyn-type-mismatch-2.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/return-dyn-type-mismatch-2.rs:7:5 + | +LL | fn foo() -> dyn Trait + | ------------ expected `(dyn Trait + 'static)` because of return type +... +LL | 42 + | ^^ expected `dyn Trait`, found integer + | + = note: expected trait object `(dyn Trait + 'static)` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/return-dyn-type-mismatch.rs b/tests/ui/typeck/return-dyn-type-mismatch.rs new file mode 100644 index 00000000000..93718f70f41 --- /dev/null +++ b/tests/ui/typeck/return-dyn-type-mismatch.rs @@ -0,0 +1,21 @@ +pub trait TestTrait { + type MyType; + + fn func() -> Option + where + Self: Sized; +} + +impl dyn TestTrait +where + Self: Sized, // pesky sized predicate +{ + fn other_func() -> dyn TestTrait { + match Self::func() { + None => None, + //~^ ERROR mismatched types + } + } +} + +fn main() {} diff --git a/tests/ui/typeck/return-dyn-type-mismatch.stderr b/tests/ui/typeck/return-dyn-type-mismatch.stderr new file mode 100644 index 00000000000..9d0a609d87f --- /dev/null +++ b/tests/ui/typeck/return-dyn-type-mismatch.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/return-dyn-type-mismatch.rs:15:21 + | +LL | fn other_func() -> dyn TestTrait { + | ------------------------- expected `(dyn TestTrait + 'static)` because of return type +LL | match Self::func() { +LL | None => None, + | ^^^^ expected `dyn TestTrait`, found `Option<_>` + | + = note: expected trait object `(dyn TestTrait + 'static)` + found enum `Option<_>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From bff5ecd382f60f01255a4171363f11e2b206b4e8 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 3 Jun 2023 11:24:19 +0800 Subject: [PATCH 10/11] only check when we specify rustc in config.toml --- src/bootstrap/Cargo.lock | 7 +++++++ src/bootstrap/Cargo.toml | 1 + src/bootstrap/config.rs | 45 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 311ac175160..8f8778efee7 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -58,6 +58,7 @@ dependencies = [ "once_cell", "opener", "pretty_assertions", + "semver", "serde", "serde_derive", "serde_json", @@ -645,6 +646,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "serde" version = "1.0.160" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 70ade776d7d..367c6190967 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -57,6 +57,7 @@ walkdir = "2" sysinfo = { version = "0.26.0", optional = true } clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.2.2" +semver = "1.0.17" # Solaris doesn't support flock() and thus fd-lock is not option now [target.'cfg(not(target_os = "solaris"))'.dependencies] diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 45ad1547eb7..8ea7e836375 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -25,6 +25,7 @@ use crate::flags::{Color, Flags, Warnings}; use crate::util::{exe, output, t}; use build_helper::detail_exit_macro; use once_cell::sync::OnceCell; +use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1114,10 +1115,14 @@ impl Config { config.out = crate::util::absolute(&config.out); } - config.initial_rustc = build.rustc.map(PathBuf::from).unwrap_or_else(|| { + config.initial_rustc = if let Some(rustc) = build.rustc { + config.check_build_rustc_version(&rustc); + PathBuf::from(rustc) + } else { config.download_beta_toolchain(); config.out.join(config.build.triple).join("stage0/bin/rustc") - }); + }; + config.initial_cargo = build .cargo .map(|cargo| { @@ -1779,6 +1784,42 @@ impl Config { self.rust_codegen_backends.get(0).cloned() } + pub fn check_build_rustc_version(&self, rustc_path: &str) { + if self.dry_run() { + return; + } + + // check rustc version is same or lower with 1 apart from the building one + let mut cmd = Command::new(rustc_path); + cmd.arg("--version"); + let rustc_output = output(&mut cmd) + .lines() + .next() + .unwrap() + .split(' ') + .nth(1) + .unwrap() + .split('-') + .next() + .unwrap() + .to_owned(); + let rustc_version = Version::parse(&rustc_output.trim()).unwrap(); + let source_version = + Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim()) + .unwrap(); + if !(source_version == rustc_version + || (source_version.major == rustc_version.major + && source_version.minor == rustc_version.minor + 1)) + { + let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1); + eprintln!( + "Unexpected rustc version: {}, we should use {}/{} to build source with {}", + rustc_version, prev_version, source_version, source_version + ); + detail_exit_macro!(1); + } + } + /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. fn download_ci_rustc_commit(&self, download_rustc: Option) -> Option { // If `download-rustc` is not set, default to rebuilding. From 268b08b01bfd95d315c03a9e3a69f254176b2a35 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 3 Jun 2023 17:17:56 +0200 Subject: [PATCH 11/11] do not use ty_adt_id from internal trait --- .../src/traits/error_reporting/suggestions.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9f2740a3898..1044613c585 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -27,7 +27,6 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime}; use rustc_middle::hir::map; -use rustc_middle::query::Key; use rustc_middle::ty::error::TypeError::{self, Sorts}; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, @@ -3701,8 +3700,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let Some(typeck_results) = self.typeck_results.as_ref() else { return }; // Make sure we're dealing with the `Option` type. - let Some(ty_adt_did) = typeck_results.expr_ty_adjusted(expr).ty_adt_id() else { return }; - if !tcx.is_diagnostic_item(sym::Option, ty_adt_did) { + let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else { return }; + if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) { return; }