@@ -6,10 +6,10 @@ use rustc_errors::codes::*;
66use rustc_errors:: {
77 Applicability , Diag , ErrorGuaranteed , MultiSpan , StashKey , a_or_an, listify, pluralize,
88} ;
9- use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
9+ use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
1010use rustc_hir:: def_id:: DefId ;
1111use rustc_hir:: intravisit:: Visitor ;
12- use rustc_hir:: { ExprKind , HirId , Node , QPath } ;
12+ use rustc_hir:: { ExprKind , HirId , LangItem , Node , QPath } ;
1313use rustc_hir_analysis:: check:: intrinsicck:: InlineAsmCtxt ;
1414use rustc_hir_analysis:: check:: potentially_plural_count;
1515use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
@@ -119,6 +119,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
119119 }
120120 }
121121
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+
122180 pub ( in super :: super ) fn check_method_argument_types (
123181 & self ,
124182 sp : Span ,
0 commit comments