Skip to content

Commit d117135

Browse files
committed
Auto merge of #106253 - nbdd0121:upcast, r=compiler-errors
Skip possible where_clause_object_safety lints when checking `multiple_supertrait_upcastable` Fix #106247 To achieve this, I lifted the `WhereClauseReferencesSelf` out from `object_safety_violations` and move it into `is_object_safe` (which is changed to a new query). cc `@dtolnay` r? `@compiler-errors`
2 parents a29efcc + 66f3ab9 commit d117135

File tree

26 files changed

+219
-28
lines changed

26 files changed

+219
-28
lines changed

compiler/rustc_error_messages/locales/en-US/lint.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ lint_cstring_ptr = getting the inner pointer of a temporary `CString`
100100
.note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
101101
.help = for more information, see https://doc.rust-lang.org/reference/destructors.html
102102
103+
lint_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
104+
103105
lint_identifier_non_ascii_char = identifier contains non-ASCII characters
104106
105107
lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints

compiler/rustc_feature/src/active.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ declare_features! (
160160
(active, intrinsics, "1.0.0", None, None),
161161
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
162162
(active, lang_items, "1.0.0", None, None),
163+
/// Allows the `multiple_supertrait_upcastable` lint.
164+
(active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
163165
/// Allows using `#[omit_gdb_pretty_printer_section]`.
164166
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
165167
/// Allows using `#[prelude_import]` on glob `use` items.

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
841841
_ => {}
842842
}
843843
if !trait_should_be_self.is_empty() {
844-
if tcx.object_safety_violations(trait_def_id).is_empty() {
844+
if tcx.check_is_object_safe(trait_def_id) {
845845
return;
846846
}
847847
let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();

compiler/rustc_hir_analysis/src/coherence/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ fn check_object_overlap<'tcx>(
169169
});
170170

171171
for component_def_id in component_def_ids {
172-
if !tcx.is_object_safe(component_def_id) {
172+
if !tcx.check_is_object_safe(component_def_id) {
173173
// Without the 'object_safe_for_dispatch' feature this is an error
174174
// which will be reported by wfcheck. Ignore it here.
175175
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1823,7 +1823,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
18231823
.trait_ref()
18241824
.and_then(|t| t.trait_def_id())
18251825
.map_or(false, |def_id| {
1826-
fcx.tcx.object_safety_violations(def_id).is_empty()
1826+
fcx.tcx.check_is_object_safe(def_id)
18271827
})
18281828
})
18291829
}

compiler/rustc_lint/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ mod let_underscore;
6464
mod levels;
6565
mod lints;
6666
mod methods;
67+
mod multiple_supertrait_upcastable;
6768
mod non_ascii_idents;
6869
mod non_fmt_panic;
6970
mod nonstandard_style;
@@ -98,6 +99,7 @@ use hidden_unicode_codepoints::*;
9899
use internal::*;
99100
use let_underscore::*;
100101
use methods::*;
102+
use multiple_supertrait_upcastable::*;
101103
use non_ascii_idents::*;
102104
use non_fmt_panic::NonPanicFmt;
103105
use nonstandard_style::*;
@@ -232,6 +234,7 @@ late_lint_methods!(
232234
InvalidAtomicOrdering: InvalidAtomicOrdering,
233235
NamedAsmLabels: NamedAsmLabels,
234236
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
237+
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
235238
]
236239
]
237240
);

compiler/rustc_lint/src/lints.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,13 @@ pub struct CStringPtr {
917917
pub unwrap: Span,
918918
}
919919

920+
// multiple_supertrait_upcastable.rs
921+
#[derive(LintDiagnostic)]
922+
#[diag(lint_multple_supertrait_upcastable)]
923+
pub struct MultipleSupertraitUpcastable {
924+
pub ident: Ident,
925+
}
926+
920927
// non_ascii_idents.rs
921928
#[derive(LintDiagnostic)]
922929
#[diag(lint_identifier_non_ascii_char)]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::{LateContext, LateLintPass, LintContext};
2+
3+
use rustc_hir as hir;
4+
use rustc_span::sym;
5+
6+
declare_lint! {
7+
/// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
8+
/// supertraits.
9+
///
10+
/// ### Example
11+
///
12+
/// ```rust
13+
/// trait A {}
14+
/// trait B {}
15+
///
16+
/// #[warn(multiple_supertrait_upcastable)]
17+
/// trait C: A + B {}
18+
/// ```
19+
///
20+
/// {{produces}}
21+
///
22+
/// ### Explanation
23+
///
24+
/// To support upcasting with multiple supertraits, we need to store multiple vtables and this
25+
/// can result in extra space overhead, even if no code actually uses upcasting.
26+
/// This lint allows users to identify when such scenarios occur and to decide whether the
27+
/// additional overhead is justified.
28+
pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
29+
Allow,
30+
"detect when an object-safe trait has multiple supertraits",
31+
@feature_gate = sym::multiple_supertrait_upcastable;
32+
}
33+
34+
declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
35+
36+
impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
37+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
38+
let def_id = item.owner_id.to_def_id();
39+
// NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because
40+
// the latter will report `where_clause_object_safety` lint.
41+
if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
42+
&& cx.tcx.object_safety_violations(def_id).is_empty()
43+
{
44+
let direct_super_traits_iter = cx.tcx
45+
.super_predicates_of(def_id)
46+
.predicates
47+
.into_iter()
48+
.filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
49+
if direct_super_traits_iter.count() > 1 {
50+
cx.emit_spanned_lint(
51+
MULTIPLE_SUPERTRAIT_UPCASTABLE,
52+
cx.tcx.def_span(def_id),
53+
crate::lints::MultipleSupertraitUpcastable {
54+
ident: item.ident
55+
},
56+
);
57+
}
58+
}
59+
}
60+
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,9 @@ rustc_queries! {
12741274
query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
12751275
desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
12761276
}
1277+
query check_is_object_safe(trait_id: DefId) -> bool {
1278+
desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) }
1279+
}
12771280

12781281
/// Gets the ParameterEnvironment for a given item; this environment
12791282
/// will be in "user-facing" mode, meaning that it is suitable for

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,10 +2458,6 @@ impl<'tcx> TyCtxt<'tcx> {
24582458
}
24592459
}
24602460

2461-
pub fn is_object_safe(self, key: DefId) -> bool {
2462-
self.object_safety_violations(key).is_empty()
2463-
}
2464-
24652461
#[inline]
24662462
pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
24672463
matches!(

0 commit comments

Comments
 (0)