11use rustc_abi:: { Align , Size } ;
22use rustc_ast:: { IntTy , LitIntType , LitKind , UintTy } ;
3- use rustc_hir:: attrs:: { IntType , ReprAttr } ;
3+ use rustc_hir:: attrs:: { AttrConstResolved , AttrIntValue , IntType , ReprAttr } ;
4+ use rustc_hir:: def:: { DefKind , Res } ;
5+ use rustc_session:: parse:: feature_err;
46
57use super :: prelude:: * ;
6- use crate :: session_diagnostics:: { self , IncorrectReprFormatGenericCause } ;
8+ use crate :: ShouldEmit ;
9+ use crate :: session_diagnostics:: {
10+ self , AttrConstGenericNotSupported , AttrConstPathNotConst , IncorrectReprFormatGenericCause ,
11+ } ;
712
813/// Parse #[repr(...)] forms.
914///
@@ -122,7 +127,7 @@ fn parse_repr<S: Stage>(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -
122127 parse_repr_align ( cx, l, param. span ( ) , AlignKind :: Align )
123128 }
124129
125- ( Some ( sym:: packed) , ArgParser :: NoArgs ) => Some ( ReprPacked ( Align :: ONE ) ) ,
130+ ( Some ( sym:: packed) , ArgParser :: NoArgs ) => Some ( ReprPacked ( AttrIntValue :: Lit ( 1 ) ) ) ,
126131 ( Some ( sym:: packed) , ArgParser :: List ( l) ) => {
127132 parse_repr_align ( cx, l, param. span ( ) , AlignKind :: Packed )
128133 }
@@ -189,6 +194,11 @@ enum AlignKind {
189194 Align ,
190195}
191196
197+ enum AlignmentParseError {
198+ Message ( String ) ,
199+ AlreadyErrored ,
200+ }
201+
192202fn parse_repr_align < S : Stage > (
193203 cx : & AcceptContext < ' _ , ' _ , S > ,
194204 list : & MetaItemListParser ,
@@ -214,31 +224,21 @@ fn parse_repr_align<S: Stage>(
214224 return None ;
215225 } ;
216226
217- let Some ( lit) = align. lit ( ) else {
227+ match parse_alignment_or_const_path (
228+ cx,
229+ align,
218230 match align_kind {
219- Packed => {
220- cx. emit_err ( session_diagnostics:: IncorrectReprFormatPackedExpectInteger {
221- span : align. span ( ) ,
222- } ) ;
223- }
224- Align => {
225- cx. emit_err ( session_diagnostics:: IncorrectReprFormatExpectInteger {
226- span : align. span ( ) ,
227- } ) ;
228- }
229- }
230-
231- return None ;
232- } ;
233-
234- match parse_alignment ( & lit. kind , cx) {
235- Ok ( literal) => Some ( match align_kind {
236- AlignKind :: Packed => ReprAttr :: ReprPacked ( literal) ,
237- AlignKind :: Align => ReprAttr :: ReprAlign ( literal) ,
231+ Packed => "repr(packed)" ,
232+ Align => "repr(align)" ,
233+ } ,
234+ ) {
235+ Ok ( value) => Some ( match align_kind {
236+ AlignKind :: Packed => ReprAttr :: ReprPacked ( value) ,
237+ AlignKind :: Align => ReprAttr :: ReprAlign ( value) ,
238238 } ) ,
239- Err ( message) => {
239+ Err ( AlignmentParseError :: Message ( message) ) => {
240240 cx. emit_err ( session_diagnostics:: InvalidReprGeneric {
241- span : lit . span ,
241+ span : align . span ( ) ,
242242 repr_arg : match align_kind {
243243 Packed => "packed" . to_string ( ) ,
244244 Align => "align" . to_string ( ) ,
@@ -247,6 +247,7 @@ fn parse_repr_align<S: Stage>(
247247 } ) ;
248248 None
249249 }
250+ Err ( AlignmentParseError :: AlreadyErrored ) => None ,
250251 }
251252}
252253
@@ -281,9 +282,71 @@ fn parse_alignment<S: Stage>(
281282 Ok ( align)
282283}
283284
285+ fn parse_alignment_or_const_path < S : Stage > (
286+ cx : & AcceptContext < ' _ , ' _ , S > ,
287+ arg : & MetaItemOrLitParser ,
288+ attr_name : & ' static str ,
289+ ) -> Result < AttrIntValue , AlignmentParseError > {
290+ if let Some ( lit) = arg. lit ( ) {
291+ return parse_alignment ( & lit. kind , cx)
292+ . map ( |align| AttrIntValue :: Lit ( u128:: from ( align. bytes ( ) ) ) )
293+ . map_err ( AlignmentParseError :: Message ) ;
294+ }
295+
296+ let Some ( meta) = arg. meta_item ( ) else {
297+ return Err ( AlignmentParseError :: Message ( "not an unsuffixed integer" . to_string ( ) ) ) ;
298+ } ;
299+
300+ if !matches ! ( meta. args( ) , ArgParser :: NoArgs ) {
301+ return Err ( AlignmentParseError :: Message ( "not an unsuffixed integer" . to_string ( ) ) ) ;
302+ }
303+
304+ if let Some ( features) = cx. features_option ( )
305+ && !features. const_attr_paths ( )
306+ && !meta. span ( ) . allows_unstable ( sym:: const_attr_paths)
307+ {
308+ feature_err (
309+ cx. sess ( ) ,
310+ sym:: const_attr_paths,
311+ meta. span ( ) ,
312+ "const item paths in builtin attributes are experimental" ,
313+ )
314+ . emit ( ) ;
315+ return Err ( AlignmentParseError :: AlreadyErrored ) ;
316+ }
317+
318+ let Some ( resolution) = cx. attr_const_resolution ( meta. path ( ) . span ( ) ) else {
319+ // `parse_limited(sym::repr)` runs before lowering for callers that only care whether
320+ // `repr(packed(...))` exists at all.
321+ if matches ! ( cx. stage. should_emit( ) , ShouldEmit :: Nothing ) {
322+ return Ok ( AttrIntValue :: Lit ( 1 ) ) ;
323+ }
324+ return Err ( AlignmentParseError :: Message ( "not an unsuffixed integer" . to_string ( ) ) ) ;
325+ } ;
326+
327+ match resolution {
328+ AttrConstResolved :: Resolved ( Res :: Def ( DefKind :: Const { .. } , def_id) ) => {
329+ Ok ( AttrIntValue :: Const { def_id, span : meta. path ( ) . span ( ) } )
330+ }
331+ AttrConstResolved :: Resolved ( Res :: Def ( DefKind :: ConstParam , _) ) => {
332+ cx. emit_err ( AttrConstGenericNotSupported { span : meta. path ( ) . span ( ) , attr_name } ) ;
333+ Err ( AlignmentParseError :: AlreadyErrored )
334+ }
335+ AttrConstResolved :: Resolved ( res) => {
336+ cx. emit_err ( AttrConstPathNotConst {
337+ span : meta. path ( ) . span ( ) ,
338+ attr_name,
339+ thing : res. descr ( ) ,
340+ } ) ;
341+ Err ( AlignmentParseError :: AlreadyErrored )
342+ }
343+ AttrConstResolved :: Error => Err ( AlignmentParseError :: AlreadyErrored ) ,
344+ }
345+ }
346+
284347/// Parse #[align(N)].
285348#[ derive( Default ) ]
286- pub ( crate ) struct RustcAlignParser ( Option < ( Align , Span ) > ) ;
349+ pub ( crate ) struct RustcAlignParser ( ThinVec < ( AttrIntValue , Span ) > ) ;
287350
288351impl RustcAlignParser {
289352 const PATH : & [ Symbol ] = & [ sym:: rustc_align] ;
@@ -301,22 +364,15 @@ impl RustcAlignParser {
301364 return ;
302365 } ;
303366
304- let Some ( lit) = align. lit ( ) else {
305- cx. emit_err ( session_diagnostics:: IncorrectReprFormatExpectInteger {
306- span : align. span ( ) ,
307- } ) ;
308-
309- return ;
310- } ;
311-
312- match parse_alignment ( & lit. kind , cx) {
313- Ok ( literal) => self . 0 = Ord :: max ( self . 0 , Some ( ( literal, cx. attr_span ) ) ) ,
314- Err ( message) => {
367+ match parse_alignment_or_const_path ( cx, align, "rustc_align" ) {
368+ Ok ( literal) => self . 0 . push ( ( literal, cx. attr_span ) ) ,
369+ Err ( AlignmentParseError :: Message ( message) ) => {
315370 cx. emit_err ( session_diagnostics:: InvalidAlignmentValue {
316- span : lit . span ,
371+ span : align . span ( ) ,
317372 error_part : message,
318373 } ) ;
319374 }
375+ Err ( AlignmentParseError :: AlreadyErrored ) => { }
320376 }
321377 }
322378 }
@@ -335,8 +391,7 @@ impl<S: Stage> AttributeParser<S> for RustcAlignParser {
335391 ] ) ;
336392
337393 fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
338- let ( align, span) = self . 0 ?;
339- Some ( AttributeKind :: RustcAlign { align, span } )
394+ ( !self . 0 . is_empty ( ) ) . then_some ( AttributeKind :: RustcAlign { aligns : self . 0 } )
340395 }
341396}
342397
@@ -358,7 +413,6 @@ impl<S: Stage> AttributeParser<S> for RustcAlignStaticParser {
358413 AllowedTargets :: AllowList ( & [ Allow ( Target :: Static ) , Allow ( Target :: ForeignStatic ) ] ) ;
359414
360415 fn finalize ( self , _cx : & FinalizeContext < ' _ , ' _ , S > ) -> Option < AttributeKind > {
361- let ( align, span) = self . 0 . 0 ?;
362- Some ( AttributeKind :: RustcAlign { align, span } )
416+ ( !self . 0 . 0 . is_empty ( ) ) . then_some ( AttributeKind :: RustcAlign { aligns : self . 0 . 0 } )
363417 }
364418}
0 commit comments