@@ -331,18 +331,29 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
331
331
} else if let Def :: NonMacroAttr ( attr_kind) = def {
332
332
let is_attr_invoc =
333
333
if let InvocationKind :: Attr { .. } = invoc. kind { true } else { false } ;
334
+ let path = invoc. path ( ) . expect ( "no path for non-macro attr" ) ;
334
335
match attr_kind {
335
- NonMacroAttrKind :: Tool | NonMacroAttrKind :: DeriveHelper if is_attr_invoc => {
336
+ NonMacroAttrKind :: Tool | NonMacroAttrKind :: DeriveHelper |
337
+ NonMacroAttrKind :: Custom if is_attr_invoc => {
336
338
if attr_kind == NonMacroAttrKind :: Tool &&
337
339
!self . session . features_untracked ( ) . tool_attributes {
338
340
feature_err ( & self . session . parse_sess , "tool_attributes" ,
339
341
invoc. span ( ) , GateIssue :: Language ,
340
342
"tool attributes are unstable" ) . emit ( ) ;
341
343
}
342
- return Ok ( Some ( Lrc :: new ( SyntaxExtension :: NonMacroAttr ) ) ) ;
344
+ if attr_kind == NonMacroAttrKind :: Custom &&
345
+ !self . session . features_untracked ( ) . custom_attribute {
346
+ let msg = format ! ( "The attribute `{}` is currently unknown to the compiler \
347
+ and may have meaning added to it in the future", path) ;
348
+ feature_err ( & self . session . parse_sess , "custom_attribute" , invoc. span ( ) ,
349
+ GateIssue :: Language , & msg) . emit ( ) ;
350
+ }
351
+ return Ok ( Some ( Lrc :: new ( SyntaxExtension :: NonMacroAttr {
352
+ mark_used : attr_kind == NonMacroAttrKind :: Tool ,
353
+ } ) ) ) ;
343
354
}
344
355
_ => {
345
- self . report_non_macro_attr ( invoc . path_span ( ) , def) ;
356
+ self . report_non_macro_attr ( path . span , def) ;
346
357
return Err ( Determinacy :: Determined ) ;
347
358
}
348
359
}
@@ -418,43 +429,42 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
418
429
} ;
419
430
420
431
let path = attr. as_ref ( ) . unwrap ( ) . path . clone ( ) ;
421
- let mut determinacy = Determinacy :: Determined ;
422
- match self . resolve_macro_to_def ( scope, & path, MacroKind :: Attr , force) {
423
- Ok ( def) => return Ok ( def) ,
424
- Err ( Determinacy :: Undetermined ) => determinacy = Determinacy :: Undetermined ,
425
- Err ( Determinacy :: Determined ) if force => return Err ( Determinacy :: Determined ) ,
426
- Err ( Determinacy :: Determined ) => { }
432
+ let def = self . resolve_macro_to_def ( scope, & path, MacroKind :: Attr , force) ;
433
+ if let Ok ( Def :: NonMacroAttr ( NonMacroAttrKind :: Custom ) ) = def { } else {
434
+ return def;
427
435
}
428
436
429
- // Ok at this point we've determined that the `attr` above doesn't
430
- // actually resolve at this time, so we may want to report an error.
431
- // It could be the case, though, that `attr` won't ever resolve! If
432
- // there's a custom derive that could be used it might declare `attr` as
433
- // a custom attribute accepted by the derive. In this case we don't want
434
- // to report this particular invocation as unresolved, but rather we'd
435
- // want to move on to the next invocation.
437
+ // At this point we've found that the `attr` is determinately unresolved and thus can be
438
+ // interpreted as a custom attribute. Normally custom attributes are feature gated, but
439
+ // it may be a custom attribute whitelisted by a derive macro and they do not require
440
+ // a feature gate.
436
441
//
437
- // This loop here looks through all of the derive annotations in scope
438
- // and tries to resolve them. If they themselves successfully resolve
439
- // *and* the resolve mentions that this attribute's name is a registered
440
- // custom attribute then we return that custom attribute as the resolution result.
441
- let attr_name = match path. segments . len ( ) {
442
- 1 => path. segments [ 0 ] . ident . name ,
443
- _ => return Err ( determinacy) ,
444
- } ;
442
+ // So here we look through all of the derive annotations in scope and try to resolve them.
443
+ // If they themselves successfully resolve *and* one of the resolved derive macros
444
+ // whitelists this attribute's name, then this is a registered attribute and we can convert
445
+ // it from a "generic custom attrite" into a "known derive helper attribute".
446
+ enum ConvertToDeriveHelper { Yes , No , DontKnow }
447
+ let mut convert_to_derive_helper = ConvertToDeriveHelper :: No ;
448
+ let attr_name = path. segments [ 0 ] . ident . name ;
445
449
for path in traits {
446
450
match self . resolve_macro ( scope, path, MacroKind :: Derive , force) {
447
451
Ok ( ext) => if let SyntaxExtension :: ProcMacroDerive ( _, ref inert_attrs, _) = * ext {
448
452
if inert_attrs. contains ( & attr_name) {
449
- return Ok ( Def :: NonMacroAttr ( NonMacroAttrKind :: DeriveHelper ) ) ;
453
+ convert_to_derive_helper = ConvertToDeriveHelper :: Yes ;
454
+ break
450
455
}
451
456
} ,
452
- Err ( Determinacy :: Undetermined ) => determinacy = Determinacy :: Undetermined ,
457
+ Err ( Determinacy :: Undetermined ) =>
458
+ convert_to_derive_helper = ConvertToDeriveHelper :: DontKnow ,
453
459
Err ( Determinacy :: Determined ) => { }
454
460
}
455
461
}
456
462
457
- Err ( determinacy)
463
+ match convert_to_derive_helper {
464
+ ConvertToDeriveHelper :: Yes => Ok ( Def :: NonMacroAttr ( NonMacroAttrKind :: DeriveHelper ) ) ,
465
+ ConvertToDeriveHelper :: No => def,
466
+ ConvertToDeriveHelper :: DontKnow => Err ( Determinacy :: determined ( force) ) ,
467
+ }
458
468
}
459
469
460
470
fn resolve_macro_to_def ( & mut self , scope : Mark , path : & ast:: Path , kind : MacroKind , force : bool )
@@ -537,10 +547,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
537
547
let result = if let Some ( MacroBinding :: Legacy ( binding) ) = legacy_resolution {
538
548
Ok ( Def :: Macro ( binding. def_id , MacroKind :: Bang ) )
539
549
} else {
540
- match self . resolve_lexical_macro_path_segment ( path[ 0 ] , MacroNS , false , span) {
550
+ match self . resolve_lexical_macro_path_segment ( path[ 0 ] , MacroNS , false , force,
551
+ kind == MacroKind :: Attr , span) {
541
552
Ok ( binding) => Ok ( binding. binding ( ) . def_ignoring_ambiguity ( ) ) ,
542
- Err ( Determinacy :: Undetermined ) if !force => return Err ( Determinacy :: Undetermined ) ,
543
- Err ( _ ) => {
553
+ Err ( Determinacy :: Undetermined ) => return Err ( Determinacy :: Undetermined ) ,
554
+ Err ( Determinacy :: Determined ) => {
544
555
self . found_unresolved_macro = true ;
545
556
Err ( Determinacy :: Determined )
546
557
}
@@ -561,6 +572,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
561
572
mut ident : Ident ,
562
573
ns : Namespace ,
563
574
record_used : bool ,
575
+ force : bool ,
576
+ is_attr : bool ,
564
577
path_span : Span )
565
578
-> Result < MacroBinding < ' a > , Determinacy > {
566
579
// General principles:
@@ -591,6 +604,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
591
604
// 3. Builtin attributes (closed, controlled).
592
605
593
606
assert ! ( ns == TypeNS || ns == MacroNS ) ;
607
+ let force = force || record_used;
594
608
ident = ident. modern ( ) ;
595
609
596
610
// Names from inner scope that can't shadow names from outer scopes, e.g.
@@ -764,7 +778,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
764
778
Err ( Determinacy :: Determined ) => {
765
779
continue_search ! ( ) ;
766
780
}
767
- Err ( Determinacy :: Undetermined ) => return Err ( Determinacy :: Undetermined ) ,
781
+ Err ( Determinacy :: Undetermined ) => return Err ( Determinacy :: determined ( force ) ) ,
768
782
}
769
783
}
770
784
@@ -773,7 +787,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
773
787
return Ok ( previous_result) ;
774
788
}
775
789
776
- if record_used { Err ( Determinacy :: Determined ) } else { Err ( Determinacy :: Undetermined ) }
790
+ let determinacy = Determinacy :: determined ( force) ;
791
+ if determinacy == Determinacy :: Determined && is_attr {
792
+ // For attributes interpret determinate "no solution" as a custom attribute.
793
+ let binding = ( Def :: NonMacroAttr ( NonMacroAttrKind :: Custom ) ,
794
+ ty:: Visibility :: Public , ident. span , Mark :: root ( ) )
795
+ . to_name_binding ( self . arenas ) ;
796
+ Ok ( MacroBinding :: Global ( binding) )
797
+ } else {
798
+ Err ( determinacy)
799
+ }
777
800
}
778
801
779
802
pub fn resolve_legacy_scope ( & mut self ,
@@ -857,7 +880,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
857
880
let span = ident. span ;
858
881
let legacy_scope = & self . invocations [ & mark] . legacy_scope ;
859
882
let legacy_resolution = self . resolve_legacy_scope ( legacy_scope, ident, true ) ;
860
- let resolution = self . resolve_lexical_macro_path_segment ( ident, MacroNS , true , span) ;
883
+ let resolution = self . resolve_lexical_macro_path_segment ( ident, MacroNS , true , true ,
884
+ kind == MacroKind :: Attr , span) ;
861
885
862
886
let check_consistency = |this : & Self , binding : MacroBinding | {
863
887
if let Some ( def) = def {
0 commit comments