@@ -2,13 +2,15 @@ use std::path::PathBuf;
22
33use rustc_ast:: { LitIntType , LitKind , MetaItemLit } ;
44use rustc_feature:: AttributeStability ;
5- use rustc_hir:: LangItem ;
65use rustc_hir:: attrs:: {
76 BorrowckGraphvizFormatKind , CguFields , CguKind , DivergingBlockBehavior ,
8- DivergingFallbackBehavior , RustcCleanAttribute , RustcCleanQueries , RustcMirKind ,
7+ DivergingFallbackBehavior , EditionRedirect , RustcCleanAttribute , RustcCleanQueries ,
8+ RustcMirKind ,
99} ;
1010use rustc_hir:: target:: GenericParamKind ;
11+ use rustc_hir:: { LangItem , find_attr} ;
1112use rustc_span:: Symbol ;
13+ use rustc_span:: edition:: Edition ;
1214
1315use super :: prelude:: * ;
1416use super :: util:: parse_single_integer;
@@ -329,6 +331,118 @@ impl AttributeParser for RustcCguTestAttributeParser {
329331 }
330332}
331333
334+ pub ( crate ) struct RustcEditionRedirectParser ;
335+
336+ impl CombineAttributeParser for RustcEditionRedirectParser {
337+ const PATH : & [ Symbol ] = & [ sym:: rustc_edition_redirect] ;
338+ type Item = EditionRedirect ;
339+ const CONVERT : ConvertFn < Self :: Item > = |items, _| AttributeKind :: RustcEditionRedirect ( items) ;
340+ const ALLOWED_TARGETS : AllowedTargets < ' _ > = AllowedTargets :: AllowList ( & [
341+ Allow ( Target :: Const ) ,
342+ Allow ( Target :: Enum ) ,
343+ Allow ( Target :: ExternCrate ) ,
344+ Allow ( Target :: Fn ) ,
345+ Allow ( Target :: MacroDef ) ,
346+ Allow ( Target :: Mod ) ,
347+ Allow ( Target :: Static ) ,
348+ Allow ( Target :: Struct ) ,
349+ Allow ( Target :: Trait ) ,
350+ Allow ( Target :: TraitAlias ) ,
351+ Allow ( Target :: TyAlias ) ,
352+ Allow ( Target :: Union ) ,
353+ Allow ( Target :: Use ) ,
354+ ] ) ;
355+ const TEMPLATE : AttributeTemplate =
356+ template ! ( List : & [ r#"before = "2024", target(path::to::item)"# ] ) ;
357+ const STABILITY : AttributeStability = unstable ! ( edition_redirect) ;
358+
359+ fn extend (
360+ cx : & mut AcceptContext < ' _ , ' _ > ,
361+ args : & ArgParser ,
362+ ) -> impl IntoIterator < Item = Self :: Item > {
363+ let list = cx. expect_list ( args, cx. attr_span ) ?;
364+ let mut before = None ;
365+ let mut target = None ;
366+
367+ for item in list. mixed ( ) {
368+ let Some ( meta) = item. meta_item ( ) else {
369+ cx. adcx ( ) . expected_identifier ( item. span ( ) ) ;
370+ return None ;
371+ } ;
372+ let Some ( name) = meta. path ( ) . word ( ) else {
373+ cx. adcx ( )
374+ . expected_specific_argument ( meta. path ( ) . span ( ) , & [ sym:: before, sym:: target] ) ;
375+ return None ;
376+ } ;
377+ match name. name {
378+ sym:: before if before. is_none ( ) => {
379+ let Some ( value) =
380+ cx. expect_name_value ( meta. args ( ) , item. span ( ) , Some ( sym:: before) )
381+ else {
382+ return None ;
383+ } ;
384+ let Some ( value) = cx. expect_string_literal ( value) else { return None } ;
385+ before = Some ( value) ;
386+ }
387+ sym:: target if target. is_none ( ) => {
388+ let Some ( single) = cx. expect_single_element_list ( meta. args ( ) , item. span ( ) )
389+ else {
390+ return None ;
391+ } ;
392+ let Some ( target_path) = single. meta_item_no_args ( ) else {
393+ cx. adcx ( ) . expected_not_literal ( single. span ( ) ) ;
394+ return None ;
395+ } ;
396+ target = Some ( target_path. path ( ) . 0 . clone ( ) ) ;
397+ }
398+ sym:: before | sym:: target => {
399+ cx. adcx ( ) . duplicate_key ( item. span ( ) , name. name ) ;
400+ return None ;
401+ }
402+ _ => {
403+ cx. adcx ( ) . expected_specific_argument ( item. span ( ) , & [ sym:: before, sym:: target] ) ;
404+ return None ;
405+ }
406+ }
407+ }
408+
409+ let Some ( before) = before else {
410+ cx. dcx ( ) . span_err ( cx. attr_span , "missing `before` argument" ) ;
411+ return None ;
412+ } ;
413+ let Some ( target) = target else {
414+ cx. dcx ( ) . span_err ( cx. attr_span , "missing `target` argument" ) ;
415+ return None ;
416+ } ;
417+ let before = match before. as_str ( ) . parse :: < Edition > ( ) {
418+ Ok ( before) => before,
419+ Err ( ( ) ) => {
420+ cx. dcx ( ) . span_err ( cx. attr_span , "invalid edition in edition redirect" ) ;
421+ return None ;
422+ }
423+ } ;
424+
425+ Some ( EditionRedirect { before, target, span : cx. attr_span } )
426+ }
427+
428+ fn finalize_check ( cx : & FinalizeCheckContext < ' _ , ' _ > , _attr_span : Span ) {
429+ let redirects = find_attr ! (
430+ cx. parsed_attrs,
431+ RustcEditionRedirect ( redirects) => redirects
432+ )
433+ . unwrap ( ) ;
434+
435+ for ( index, redirect) in redirects. iter ( ) . enumerate ( ) {
436+ if redirects[ ..index] . iter ( ) . any ( |existing| existing. before == redirect. before ) {
437+ cx. emit_err ( diagnostics:: MultipleEditionRedirects {
438+ span : redirect. span ,
439+ edition : redirect. before . to_string ( ) ,
440+ } ) ;
441+ }
442+ }
443+ }
444+ }
445+
332446pub ( crate ) struct RustcDeprecatedSafe2024Parser ;
333447
334448impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {
0 commit comments