1
1
use rustc_hir:: { Expr , ExprKind , LangItem } ;
2
- use rustc_middle:: ty;
2
+ use rustc_middle:: ty:: Ty ;
3
3
use rustc_session:: { declare_lint, declare_lint_pass} ;
4
4
use rustc_span:: symbol:: { sym, Ident } ;
5
5
@@ -36,7 +36,7 @@ declare_lint! {
36
36
/// TODO
37
37
pub TEMPORARY_AS_PTR ,
38
38
Warn ,
39
- "TODO "
39
+ "detects getting the inner pointer of a temporary container "
40
40
}
41
41
42
42
declare_lint_pass ! ( TemporaryCStringAsPtr => [ TEMPORARY_CSTRING_AS_PTR , TEMPORARY_AS_PTR ] ) ;
@@ -57,33 +57,15 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
57
57
58
58
// It is called on a temporary rvalue.
59
59
let is_temp = is_temporary_rvalue ( receiver) ;
60
- tracing:: debug!( ?receiver, ?is_temp) ;
60
+ tracing:: debug!( receiver = ?receiver. kind , ?is_temp) ;
61
61
if !is_temp {
62
62
return ;
63
63
}
64
64
65
65
// The temporary value's type is array, box, Vec, String, or CString
66
66
let ty = cx. typeck_results ( ) . expr_ty ( receiver) ;
67
67
tracing:: debug!( ?ty) ;
68
-
69
- // None => not a container
70
- // Some(true) => CString
71
- // Some(false) => String, Vec, box, array
72
- let lint_is_cstring = match ty. kind ( ) {
73
- ty:: Array ( _, _) => Some ( false ) ,
74
- ty:: Adt ( def, _) if def. is_box ( ) => Some ( false ) ,
75
- ty:: Adt ( def, _) if cx. tcx . lang_items ( ) . get ( LangItem :: String ) == Some ( def. did ( ) ) => {
76
- Some ( false )
77
- }
78
- ty:: Adt ( def, _) => match cx. tcx . get_diagnostic_name ( def. did ( ) ) {
79
- Some ( sym:: Vec ) => Some ( false ) ,
80
- Some ( sym:: cstring_type) => Some ( true ) ,
81
- _ => None ,
82
- } ,
83
- _ => None ,
84
- } ;
85
- tracing:: debug!( ?lint_is_cstring) ;
86
- let Some ( is_cstring) = lint_is_cstring else {
68
+ let Some ( is_cstring) = as_container ( cx, ty) else {
87
69
return ;
88
70
} ;
89
71
@@ -106,10 +88,10 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
106
88
fn is_temporary_rvalue ( expr : & Expr < ' _ > ) -> bool {
107
89
match expr. kind {
108
90
// We are not interested in these
109
- ExprKind :: Cast ( _, _) | ExprKind :: Closure ( _) | ExprKind :: Tup ( _) => false ,
91
+ ExprKind :: Cast ( _, _) | ExprKind :: Closure ( _) | ExprKind :: Tup ( _) | ExprKind :: Lit ( _ ) => false ,
110
92
111
93
// Const is not temporary.
112
- ExprKind :: ConstBlock ( _) => false ,
94
+ ExprKind :: ConstBlock ( _) | ExprKind :: Repeat ( _ , _ ) => false ,
113
95
114
96
// This is literally lvalue.
115
97
ExprKind :: Path ( _) => false ,
@@ -120,39 +102,65 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
120
102
| ExprKind :: Index ( _, _, _)
121
103
| ExprKind :: Binary ( _, _, _) => true ,
122
104
123
- // TODO: Check if x: &String, *(x).as_ptr() gets triggered
124
- ExprKind :: Unary ( _, _) => true ,
105
+ // This is likely a dereference.
106
+ ExprKind :: Unary ( _, _) => false ,
125
107
126
108
// Inner blocks are rvalues.
127
109
ExprKind :: If ( _, _, _)
128
110
| ExprKind :: Loop ( _, _, _, _)
129
111
| ExprKind :: Match ( _, _, _)
130
112
| ExprKind :: Block ( _, _) => true ,
131
113
114
+ ExprKind :: DropTemps ( inner) => is_temporary_rvalue ( inner) ,
132
115
ExprKind :: Field ( parent, _) => is_temporary_rvalue ( parent) ,
133
116
134
- // FIXME: some of these get promoted to const/'static ?
135
- ExprKind :: Struct ( _, _, _)
136
- | ExprKind :: Array ( _)
137
- | ExprKind :: Repeat ( _, _)
138
- | ExprKind :: Lit ( _) => true ,
117
+ ExprKind :: Struct ( _, _, _) => true ,
118
+ // False negatives are possible, but arrays get promoted to 'static way too often.
119
+ ExprKind :: Array ( _) => false ,
139
120
140
121
// These typecheck to `!`
141
122
ExprKind :: Break ( _, _) | ExprKind :: Continue ( _) | ExprKind :: Ret ( _) | ExprKind :: Become ( _) => {
142
123
false
143
124
}
144
125
145
126
// These typecheck to `()`
146
- ExprKind :: Assign ( _, _, _) | ExprKind :: AssignOp ( _, _, _) => false ,
127
+ ExprKind :: Assign ( _, _, _) | ExprKind :: AssignOp ( _, _, _) | ExprKind :: Yield ( _ , _ ) => false ,
147
128
148
129
// Not applicable
149
130
ExprKind :: Type ( _, _) | ExprKind :: Err ( _) | ExprKind :: Let ( _) => false ,
150
131
151
132
// These are compiler-magic macros
152
133
ExprKind :: AddrOf ( _, _, _) | ExprKind :: OffsetOf ( _, _) | ExprKind :: InlineAsm ( _) => false ,
134
+ }
135
+ }
153
136
154
- // TODO: WTF are these
155
- ExprKind :: DropTemps ( _) => todo ! ( ) ,
156
- ExprKind :: Yield ( _, _) => todo ! ( ) ,
137
+ // None => not a container
138
+ // Some(true) => CString
139
+ // Some(false) => String, Vec, box, array
140
+ fn as_container ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < bool > {
141
+ if ty. is_array ( ) {
142
+ Some ( false )
143
+ } else if ty. is_box ( ) {
144
+ let inner = ty. boxed_ty ( ) ;
145
+ // We only care about Box<[..]>, Box<str>, Box<CStr>,
146
+ // or Box<T> iff T is another type we care about
147
+ if inner. is_slice ( )
148
+ || inner. is_str ( )
149
+ || inner. ty_adt_def ( ) . is_some_and ( |def| cx. tcx . is_lang_item ( def. did ( ) , LangItem :: CStr ) )
150
+ || as_container ( cx, inner) . is_some ( )
151
+ {
152
+ Some ( false )
153
+ } else {
154
+ None
155
+ }
156
+ } else if let Some ( def) = ty. ty_adt_def ( ) {
157
+ match cx. tcx . get_diagnostic_name ( def. did ( ) ) {
158
+ Some ( sym:: cstring_type) => Some ( true ) ,
159
+ Some ( sym:: Vec ) => Some ( false ) ,
160
+ _ if cx. tcx . is_lang_item ( def. did ( ) , LangItem :: String ) => Some ( false ) ,
161
+ _ => None ,
162
+ }
163
+ } else {
164
+ None
157
165
}
158
166
}
0 commit comments