Skip to content

Commit bafc91f

Browse files
authored
Rollup merge of rust-lang#128919 - Nadrieril:lint-query-leaks, r=cjgillot
Add an internal lint that warns when accessing untracked data Some methods access data that is not tracked by the query system and should be used with caution. As suggested in rust-lang#128815 (comment), in this PR I propose a lint (modeled on the `potential_query_instability` lint) that warns when using some specially-annotatted functions. I can't tell myself if this lint would be that useful, compared to renaming `Steal::is_stolen` to `is_stolen_untracked`. This would depend on whether there are other functions we'd want to lint like this. So far it seems they're called `*_untracked`, which may be clear enough. r? `@oli-obk`
2 parents 717aec0 + 0810a03 commit bafc91f

File tree

11 files changed

+80
-35
lines changed

11 files changed

+80
-35
lines changed

compiler/rustc_data_structures/src/steal.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl<T> Steal<T> {
5757
///
5858
/// This should not be used within rustc as it leaks information not tracked
5959
/// by the query system, breaking incremental compilation.
60+
#[cfg_attr(not(bootstrap), rustc_lint_untracked_query_information)]
6061
pub fn is_stolen(&self) -> bool {
6162
self.value.borrow().is_none()
6263
}

compiler/rustc_feature/src/builtin_attrs.rs

+6
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
786786
rustc_lint_query_instability, Normal, template!(Word),
787787
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
788788
),
789+
// Used by the `rustc::untracked_query_information` lint to warn methods which
790+
// might not be stable during incremental compilation.
791+
rustc_attr!(
792+
rustc_lint_untracked_query_information, Normal, template!(Word),
793+
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
794+
),
789795
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
790796
// APIs. Any function with this attribute will be checked by that lint.
791797
rustc_attr!(

compiler/rustc_lint/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,9 @@ lint_ptr_null_checks_ref = references are not nullable, so checking them for nul
695695
lint_query_instability = using `{$query}` can result in unstable query results
696696
.note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
697697
698+
lint_query_untracked = `{$method}` accesses information that is not tracked by the query system
699+
.note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
700+
698701
lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
699702
700703
lint_range_use_inclusive_range = use an inclusive range instead

compiler/rustc_lint/src/internal.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use tracing::debug;
1717

1818
use crate::lints::{
1919
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
20-
NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag,
21-
TykindKind, UntranslatableDiag,
20+
NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, TyQualified,
21+
TykindDiag, TykindKind, UntranslatableDiag,
2222
};
2323
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
2424

@@ -88,7 +88,18 @@ declare_tool_lint! {
8888
report_in_external_macro: true
8989
}
9090

91-
declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);
91+
declare_tool_lint! {
92+
/// The `untracked_query_information` lint detects use of methods which leak information not
93+
/// tracked by the query system, such as whether a `Steal<T>` value has already been stolen. In
94+
/// order not to break incremental compilation, such methods must be used very carefully or not
95+
/// at all.
96+
pub rustc::UNTRACKED_QUERY_INFORMATION,
97+
Allow,
98+
"require explicit opt-in when accessing information not tracked by the query system",
99+
report_in_external_macro: true
100+
}
101+
102+
declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]);
92103

93104
impl LateLintPass<'_> for QueryStability {
94105
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -102,6 +113,13 @@ impl LateLintPass<'_> for QueryStability {
102113
QueryInstability { query: cx.tcx.item_name(def_id) },
103114
);
104115
}
116+
if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) {
117+
cx.emit_span_lint(
118+
UNTRACKED_QUERY_INFORMATION,
119+
span,
120+
QueryUntracked { method: cx.tcx.item_name(def_id) },
121+
);
122+
}
105123
}
106124
}
107125
}

compiler/rustc_lint/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ fn register_internals(store: &mut LintStore) {
608608
vec![
609609
LintId::of(DEFAULT_HASH_TYPES),
610610
LintId::of(POTENTIAL_QUERY_INSTABILITY),
611+
LintId::of(UNTRACKED_QUERY_INFORMATION),
611612
LintId::of(USAGE_OF_TY_TYKIND),
612613
LintId::of(PASS_BY_VALUE),
613614
LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),

compiler/rustc_lint/src/lints.rs

+7
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,13 @@ pub struct QueryInstability {
894894
pub query: Symbol,
895895
}
896896

897+
#[derive(LintDiagnostic)]
898+
#[diag(lint_query_untracked)]
899+
#[note]
900+
pub struct QueryUntracked {
901+
pub method: Symbol,
902+
}
903+
897904
#[derive(LintDiagnostic)]
898905
#[diag(lint_span_use_eq_ctxt)]
899906
pub struct SpanUseEqCtxtDiag;

compiler/rustc_passes/src/check_attr.rs

+8-32
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
125125
[sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
126126
[sym::coverage, ..] => self.check_coverage(attr, span, target),
127127
[sym::optimize, ..] => self.check_optimize(hir_id, attr, target),
128-
[sym::no_sanitize, ..] => self.check_no_sanitize(hir_id, attr, span, target),
128+
[sym::no_sanitize, ..] => {
129+
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
130+
}
129131
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
130132
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
131133
[sym::target_feature, ..] => {
@@ -166,10 +168,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
166168
self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
167169
}
168170
[sym::rustc_lint_query_instability, ..] => {
169-
self.check_rustc_lint_query_instability(hir_id, attr, span, target)
171+
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
172+
}
173+
[sym::rustc_lint_untracked_query_information, ..] => {
174+
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
170175
}
171176
[sym::rustc_lint_diagnostics, ..] => {
172-
self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
177+
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
173178
}
174179
[sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
175180
[sym::rustc_lint_opt_deny_field_access, ..] => {
@@ -451,11 +456,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
451456
}
452457
}
453458

454-
/// Checks that `#[no_sanitize(..)]` is applied to a function or method.
455-
fn check_no_sanitize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
456-
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
457-
}
458-
459459
fn check_generic_attr(
460460
&self,
461461
hir_id: HirId,
@@ -1623,30 +1623,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
16231623
}
16241624
}
16251625

1626-
/// Checks that the `#[rustc_lint_query_instability]` attribute is only applied to a function
1627-
/// or method.
1628-
fn check_rustc_lint_query_instability(
1629-
&self,
1630-
hir_id: HirId,
1631-
attr: &Attribute,
1632-
span: Span,
1633-
target: Target,
1634-
) {
1635-
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
1636-
}
1637-
1638-
/// Checks that the `#[rustc_lint_diagnostics]` attribute is only applied to a function or
1639-
/// method.
1640-
fn check_rustc_lint_diagnostics(
1641-
&self,
1642-
hir_id: HirId,
1643-
attr: &Attribute,
1644-
span: Span,
1645-
target: Target,
1646-
) {
1647-
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
1648-
}
1649-
16501626
/// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
16511627
fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
16521628
match target {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,7 @@ symbols! {
16481648
rustc_lint_opt_deny_field_access,
16491649
rustc_lint_opt_ty,
16501650
rustc_lint_query_instability,
1651+
rustc_lint_untracked_query_information,
16511652
rustc_macro_transparency,
16521653
rustc_main,
16531654
rustc_mir,

src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs

+3
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
464464
// Used by the `rustc::potential_query_instability` lint to warn methods which
465465
// might not be stable during incremental compilation.
466466
rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
467+
// Used by the `rustc::untracked_query_information` lint to warn methods which
468+
// might break incremental compilation.
469+
rustc_attr!(rustc_lint_untracked_query_information, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
467470
// Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints
468471
// to assist in changes to diagnostic APIs.
469472
rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ compile-flags: -Z unstable-options
2+
#![feature(rustc_private)]
3+
#![deny(rustc::untracked_query_information)]
4+
5+
extern crate rustc_data_structures;
6+
7+
use rustc_data_structures::steal::Steal;
8+
9+
fn use_steal(x: Steal<()>) {
10+
let _ = x.is_stolen();
11+
//~^ ERROR `is_stolen` accesses information that is not tracked by the query system
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: `is_stolen` accesses information that is not tracked by the query system
2+
--> $DIR/query_completeness.rs:10:15
3+
|
4+
LL | let _ = x.is_stolen();
5+
| ^^^^^^^^^
6+
|
7+
= note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
8+
note: the lint level is defined here
9+
--> $DIR/query_completeness.rs:3:9
10+
|
11+
LL | #![deny(rustc::untracked_query_information)]
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
error: aborting due to 1 previous error
15+

0 commit comments

Comments
 (0)