@@ -4,10 +4,10 @@ use itertools::Itertools;
44use rustc_data_structures:: fx:: FxIndexSet ;
55use rustc_errors:: codes:: * ;
66use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , MultiSpan , a_or_an, listify, pluralize} ;
7- use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
7+ use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
88use rustc_hir:: def_id:: DefId ;
99use rustc_hir:: intravisit:: Visitor ;
10- use rustc_hir:: { ExprKind , HirId , Node , QPath } ;
10+ use rustc_hir:: { ExprKind , HirId , LangItem , Node , QPath } ;
1111use rustc_hir_analysis:: check:: potentially_plural_count;
1212use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
1313use rustc_index:: IndexVec ;
@@ -104,24 +104,96 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
104104 pub ( in super :: super ) fn check_repeat_exprs ( & self ) {
105105 let mut deferred_repeat_expr_checks = self . deferred_repeat_expr_checks . borrow_mut ( ) ;
106106 debug ! ( "FnCtxt::check_repeat_exprs: {} deferred checks" , deferred_repeat_expr_checks. len( ) ) ;
107- for ( element, element_ty, count) in deferred_repeat_expr_checks. drain ( ..) {
108- // We want to emit an error if the const is not structurally resolveable as otherwise
109- // we can find up conservatively proving `Copy` which may infer the repeat expr count
110- // to something that never required `Copy` in the first place.
111- let count =
112- self . structurally_resolve_const ( element. span , self . normalize ( element. span , count) ) ;
113-
114- // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count
115- // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1.
116- if count. references_error ( ) {
117- continue ;
118- }
119107
120- // If the length is 0, we don't create any elements, so we don't copy any.
121- // If the length is 1, we don't copy that one element, we move it. Only check
122- // for `Copy` if the length is larger.
123- if count. try_to_target_usize ( self . tcx ) . is_none_or ( |x| x > 1 ) {
124- self . enforce_repeat_element_needs_copy_bound ( element, element_ty) ;
108+ let deferred_repeat_expr_checks = deferred_repeat_expr_checks
109+ . drain ( ..)
110+ . flat_map ( |( element, element_ty, count) | {
111+ // Actual constants as the repeat element are inserted repeatedly instead
112+ // of being copied via `Copy`, so we don't need to attempt to structurally
113+ // resolve the repeat count which may unnecessarily error.
114+ match & element. kind {
115+ hir:: ExprKind :: ConstBlock ( ..) => return None ,
116+ hir:: ExprKind :: Path ( qpath) => {
117+ let res = self . typeck_results . borrow ( ) . qpath_res ( qpath, element. hir_id ) ;
118+ if let Res :: Def ( DefKind :: Const | DefKind :: AssocConst , _) = res {
119+ return None ;
120+ }
121+ }
122+ _ => { }
123+ }
124+
125+ // We want to emit an error if the const is not structurally resolveable
126+ // as otherwise we can wind up conservatively proving `Copy` which may
127+ // infer the repeat expr count to something that never required `Copy` in
128+ // the first place.
129+ let count = self
130+ . structurally_resolve_const ( element. span , self . normalize ( element. span , count) ) ;
131+
132+ // Avoid run on "`NotCopy: Copy` is not implemented" errors when the
133+ // repeat expr count is erroneous/unknown. The user might wind up
134+ // specifying a repeat count of 0/1.
135+ if count. references_error ( ) {
136+ return None ;
137+ }
138+
139+ Some ( ( element, element_ty, count) )
140+ } )
141+ // We collect to force the side effects of structurally resolving the repeat
142+ // count to happen in one go, to avoid side effects from proving `Copy`
143+ // affecting whether repeat counts are known or not. If we did not do this we
144+ // would get results that depend on the order that we evaluate each repeat
145+ // expr's `Copy` check.
146+ . collect :: < Vec < _ > > ( ) ;
147+
148+ let enforce_copy_bound = |element : & hir:: Expr < ' _ > , element_ty| {
149+ // If someone calls a const fn or constructs a const value, they can extract that
150+ // out into a separate constant (or a const block in the future), so we check that
151+ // to tell them that in the diagnostic. Does not affect typeck.
152+ let is_constable = match element. kind {
153+ hir:: ExprKind :: Call ( func, _args) => match * self . node_ty ( func. hir_id ) . kind ( ) {
154+ ty:: FnDef ( def_id, _) if self . tcx . is_stable_const_fn ( def_id) => {
155+ traits:: IsConstable :: Fn
156+ }
157+ _ => traits:: IsConstable :: No ,
158+ } ,
159+ hir:: ExprKind :: Path ( qpath) => {
160+ match self . typeck_results . borrow ( ) . qpath_res ( & qpath, element. hir_id ) {
161+ Res :: Def ( DefKind :: Ctor ( _, CtorKind :: Const ) , _) => traits:: IsConstable :: Ctor ,
162+ _ => traits:: IsConstable :: No ,
163+ }
164+ }
165+ _ => traits:: IsConstable :: No ,
166+ } ;
167+
168+ let lang_item = self . tcx . require_lang_item ( LangItem :: Copy , None ) ;
169+ let code = traits:: ObligationCauseCode :: RepeatElementCopy {
170+ is_constable,
171+ elt_span : element. span ,
172+ } ;
173+ self . require_type_meets ( element_ty, element. span , code, lang_item) ;
174+ } ;
175+
176+ for ( element, element_ty, count) in deferred_repeat_expr_checks {
177+ match count. kind ( ) {
178+ ty:: ConstKind :: Value ( val) => {
179+ if val. try_to_target_usize ( self . tcx ) . is_none_or ( |count| count > 1 ) {
180+ enforce_copy_bound ( element, element_ty)
181+ } else {
182+ // If the length is 0 or 1 we don't actually copy the element, we either don't create it
183+ // or we just use the one value.
184+ }
185+ }
186+
187+ // If the length is a generic parameter or some rigid alias then conservatively
188+ // require `element_ty: Copy` as it may wind up being `>1` after monomorphization.
189+ ty:: ConstKind :: Param ( _)
190+ | ty:: ConstKind :: Expr ( _)
191+ | ty:: ConstKind :: Placeholder ( _)
192+ | ty:: ConstKind :: Unevaluated ( _) => enforce_copy_bound ( element, element_ty) ,
193+
194+ ty:: ConstKind :: Bound ( _, _) | ty:: ConstKind :: Infer ( _) | ty:: ConstKind :: Error ( _) => {
195+ unreachable ! ( )
196+ }
125197 }
126198 }
127199 }
0 commit comments