@@ -6,10 +6,10 @@ use rustc_errors::codes::*;
6
6
use rustc_errors:: {
7
7
Applicability , Diag , ErrorGuaranteed , MultiSpan , StashKey , a_or_an, listify, pluralize,
8
8
} ;
9
- use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
9
+ use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
10
10
use rustc_hir:: def_id:: DefId ;
11
11
use rustc_hir:: intravisit:: Visitor ;
12
- use rustc_hir:: { ExprKind , HirId , Node , QPath } ;
12
+ use rustc_hir:: { ExprKind , HirId , LangItem , Node , QPath } ;
13
13
use rustc_hir_analysis:: check:: intrinsicck:: InlineAsmCtxt ;
14
14
use rustc_hir_analysis:: check:: potentially_plural_count;
15
15
use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
@@ -119,6 +119,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
119
119
}
120
120
}
121
121
122
+ pub ( in super :: super ) fn check_repeat_exprs ( & self ) {
123
+ let mut deferred_repeat_expr_checks = self . deferred_repeat_expr_checks . borrow_mut ( ) ;
124
+ debug ! ( "FnCtxt::check_repeat_exprs: {} deferred checks" , deferred_repeat_expr_checks. len( ) ) ;
125
+ for ( element, element_ty, count) in deferred_repeat_expr_checks. drain ( ..) {
126
+ let count = self
127
+ . try_structurally_resolve_const ( element. span , self . normalize ( element. span , count) ) ;
128
+
129
+ // If the length is 0, we don't create any elements, so we don't copy any.
130
+ // If the length is 1, we don't copy that one element, we move it. Only check
131
+ // for `Copy` if the length is larger, or unevaluated.
132
+ if count. try_to_target_usize ( self . tcx ) . is_none_or ( |x| x > 1 ) {
133
+ self . enforce_repeat_element_needs_copy_bound ( element, element_ty) ;
134
+ }
135
+ }
136
+ }
137
+
138
+ /// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
139
+ fn enforce_repeat_element_needs_copy_bound (
140
+ & self ,
141
+ element : & hir:: Expr < ' _ > ,
142
+ element_ty : Ty < ' tcx > ,
143
+ ) {
144
+ let tcx = self . tcx ;
145
+ // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
146
+ match & element. kind {
147
+ hir:: ExprKind :: ConstBlock ( ..) => return ,
148
+ hir:: ExprKind :: Path ( qpath) => {
149
+ let res = self . typeck_results . borrow ( ) . qpath_res ( qpath, element. hir_id ) ;
150
+ if let Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: AnonConst , _) = res
151
+ {
152
+ return ;
153
+ }
154
+ }
155
+ _ => { }
156
+ }
157
+ // If someone calls a const fn or constructs a const value, they can extract that
158
+ // out into a separate constant (or a const block in the future), so we check that
159
+ // to tell them that in the diagnostic. Does not affect typeck.
160
+ let is_constable = match element. kind {
161
+ hir:: ExprKind :: Call ( func, _args) => match * self . node_ty ( func. hir_id ) . kind ( ) {
162
+ ty:: FnDef ( def_id, _) if tcx. is_stable_const_fn ( def_id) => traits:: IsConstable :: Fn ,
163
+ _ => traits:: IsConstable :: No ,
164
+ } ,
165
+ hir:: ExprKind :: Path ( qpath) => {
166
+ match self . typeck_results . borrow ( ) . qpath_res ( & qpath, element. hir_id ) {
167
+ Res :: Def ( DefKind :: Ctor ( _, CtorKind :: Const ) , _) => traits:: IsConstable :: Ctor ,
168
+ _ => traits:: IsConstable :: No ,
169
+ }
170
+ }
171
+ _ => traits:: IsConstable :: No ,
172
+ } ;
173
+
174
+ let lang_item = self . tcx . require_lang_item ( LangItem :: Copy , None ) ;
175
+ let code =
176
+ traits:: ObligationCauseCode :: RepeatElementCopy { is_constable, elt_span : element. span } ;
177
+ self . require_type_meets ( element_ty, element. span , code, lang_item) ;
178
+ }
179
+
122
180
pub ( in super :: super ) fn check_method_argument_types (
123
181
& self ,
124
182
sp : Span ,
0 commit comments