@@ -252,16 +252,43 @@ class UpdatedNodesMap : public MatchedNodeListener {
252
252
}
253
253
};
254
254
255
+ // Describing some attributes with ABI impact. The addition or removal of these
256
+ // attributes is considerred ABI-breaking.
257
+ struct ABIAttributeInfo {
258
+ const DeclAttrKind Kind;
259
+ const NodeAnnotation Annotation;
260
+ const StringRef Content;
261
+ };
262
+
255
263
class SDKContext {
256
- bool ABI;
257
264
llvm::StringSet<> TextData;
258
265
llvm::BumpPtrAllocator Allocator;
259
266
UpdatedNodesMap UpdateMap;
260
267
NodeMap TypeAliasUpdateMap;
261
268
NodeMap RevertTypeAliasUpdateMap;
262
269
TypeMemberDiffVector TypeMemberDiffs;
270
+
271
+ bool ABI;
272
+ std::vector<ABIAttributeInfo> ABIAttrs;
273
+
274
+ static StringRef getAttrName (DeclAttrKind Kind) {
275
+ switch (Kind) {
276
+ #define DECL_ATTR (NAME, CLASS, ...) case DAK_##CLASS: return " @" #NAME;
277
+ #include " swift/AST/Attr.def"
278
+ case DAK_Count:
279
+ llvm_unreachable (" unrecognized attribute kind." );
280
+ }
281
+ }
282
+
263
283
public:
264
- SDKContext (bool ABI): ABI(ABI) {}
284
+ SDKContext (bool ABI): ABI(ABI) {
285
+ #define ADD (NAME ) ABIAttrs.push_back({DeclAttrKind::DAK_##NAME, \
286
+ NodeAnnotation::Change##NAME, getAttrName (DeclAttrKind::DAK_##NAME)});
287
+ ADD (ObjC)
288
+ ADD (FixedLayout)
289
+ ADD (Frozen)
290
+ #undef ADD
291
+ }
265
292
llvm::BumpPtrAllocator &allocator () {
266
293
return Allocator;
267
294
}
@@ -281,6 +308,7 @@ class SDKContext {
281
308
return TypeMemberDiffs;
282
309
}
283
310
bool checkingABI () const { return ABI; }
311
+ ArrayRef<ABIAttributeInfo> getABIAttributeInfo () const { return ABIAttrs; }
284
312
};
285
313
286
314
// A node matcher will traverse two trees of SDKNode and find matched nodes
@@ -446,7 +474,6 @@ class SDKNodeDecl : public SDKNode {
446
474
bool IsStatic;
447
475
bool IsDeprecated;
448
476
uint8_t ReferenceOwnership;
449
- bool hasDeclAttribute (DeclAttrKind DAKind) const ;
450
477
StringRef GenericSig;
451
478
452
479
protected:
@@ -464,6 +491,7 @@ class SDKNodeDecl : public SDKNode {
464
491
StringRef getModuleName () const {return ModuleName;}
465
492
StringRef getHeaderName () const ;
466
493
ArrayRef<DeclAttrKind> getDeclAttributes () const ;
494
+ bool hasAttributeChange (const SDKNodeDecl &Another) const ;
467
495
swift::ReferenceOwnership getReferenceOwnership () const {
468
496
return swift::ReferenceOwnership (ReferenceOwnership);
469
497
}
@@ -474,7 +502,7 @@ class SDKNodeDecl : public SDKNode {
474
502
StringRef getFullyQualifiedName () const ;
475
503
bool isSDKPrivate () const ;
476
504
bool isDeprecated () const { return IsDeprecated; };
477
- bool hasFixedLayout ( ) const ;
505
+ bool hasDeclAttribute (DeclAttrKind DAKind ) const ;
478
506
bool isStatic () const { return IsStatic; };
479
507
StringRef getGenericSignature () const { return GenericSig; }
480
508
};
@@ -761,10 +789,6 @@ SDKNode *SDKNodeRoot::getInstance(SDKContext &Ctx) {
761
789
return Info.createSDKNode (SDKNodeKind::Root);
762
790
}
763
791
764
- bool SDKNodeDecl::hasFixedLayout () const {
765
- return hasDeclAttribute (DeclAttrKind::DAK_FixedLayout);
766
- }
767
-
768
792
bool SDKNodeDecl::isSDKPrivate () const {
769
793
if (getName ().startswith (" __" ))
770
794
return true ;
@@ -818,6 +842,16 @@ ArrayRef<DeclAttrKind> SDKNodeDecl::getDeclAttributes() const {
818
842
return llvm::makeArrayRef (DeclAttributes.data (), DeclAttributes.size ());
819
843
}
820
844
845
+ bool SDKNodeDecl::hasAttributeChange (const SDKNodeDecl &Another) const {
846
+ if (getDeclAttributes ().size () != Another.getDeclAttributes ().size ())
847
+ return true ;
848
+ for (auto K: getDeclAttributes ()) {
849
+ if (!Another.hasDeclAttribute (K))
850
+ return true ;
851
+ }
852
+ return false ;
853
+ }
854
+
821
855
SDKNodeDecl *SDKNodeType::getClosestParentDecl () const {
822
856
auto *Result = getParent ();
823
857
for (; !isa<SDKNodeDecl>(Result); Result = Result->getParent ());
@@ -1175,6 +1209,10 @@ bool SDKNode::operator==(const SDKNode &Other) const {
1175
1209
return false ;
1176
1210
if (Left->getReferenceOwnership () != Right->getReferenceOwnership ())
1177
1211
return false ;
1212
+ if (Left->hasAttributeChange (*Right))
1213
+ return false ;
1214
+ if (Left->getGenericSignature () != Right->getGenericSignature ())
1215
+ return false ;
1178
1216
LLVM_FALLTHROUGH;
1179
1217
}
1180
1218
case SDKNodeKind::Root: {
@@ -2454,13 +2492,19 @@ static bool isOwnershipEquivalent(ReferenceOwnership Left,
2454
2492
2455
2493
static void detectDeclChange (NodePtr L, NodePtr R) {
2456
2494
assert (L->getKind () == R->getKind ());
2495
+ auto &Ctx = L->getSDKContext ();
2457
2496
if (auto LD = dyn_cast<SDKNodeDecl>(L)) {
2458
2497
auto *RD = R->getAs <SDKNodeDecl>();
2459
2498
if (LD->isStatic () ^ RD->isStatic ())
2460
2499
L->annotate (NodeAnnotation::StaticChange);
2461
2500
if (!isOwnershipEquivalent (LD->getReferenceOwnership (),
2462
2501
RD->getReferenceOwnership ()))
2463
2502
L->annotate (NodeAnnotation::OwnershipChange);
2503
+ // Check if some attributes with ABI-impact have been added/removed.
2504
+ for (auto &Info: Ctx.getABIAttributeInfo ()) {
2505
+ if (LD->hasDeclAttribute (Info.Kind ) != RD->hasDeclAttribute (Info.Kind ))
2506
+ L->annotate (Info.Annotation );
2507
+ }
2464
2508
detectRename (L, R);
2465
2509
}
2466
2510
}
@@ -3266,6 +3310,8 @@ class DiagnosisEmitter : public SDKNodeVisitor {
3266
3310
llvm::outs () << " */\n " ;
3267
3311
removeRedundantAndSort (Diags);
3268
3312
std::for_each (Diags.begin (), Diags.end (), [](T &Diag) {
3313
+ if (Diag.isABISpecific () && !options::Abi)
3314
+ return ;
3269
3315
Diag.outputModule ();
3270
3316
Diag.output ();
3271
3317
});
@@ -3275,12 +3321,15 @@ class DiagnosisEmitter : public SDKNodeVisitor {
3275
3321
struct MetaInfo {
3276
3322
StringRef ModuleName;
3277
3323
StringRef HeaderName;
3278
- MetaInfo (const SDKNodeDecl *Node):
3279
- ModuleName (Node->getModuleName ()), HeaderName(Node->getHeaderName ()) {}
3324
+ bool IsABISpecific;
3325
+ MetaInfo (const SDKNodeDecl *Node, bool IsABISpecific = false ):
3326
+ ModuleName (Node->getModuleName ()), HeaderName(Node->getHeaderName ()),
3327
+ IsABISpecific(IsABISpecific) {}
3280
3328
};
3281
3329
3282
- struct DiagBase {
3330
+ class DiagBase {
3283
3331
MetaInfo Info;
3332
+ public:
3284
3333
DiagBase (MetaInfo Info): Info(Info) {}
3285
3334
virtual ~DiagBase () = default ;
3286
3335
void outputModule () const {
@@ -3292,6 +3341,7 @@ class DiagnosisEmitter : public SDKNodeVisitor {
3292
3341
}
3293
3342
}
3294
3343
virtual void output () const = 0;
3344
+ bool isABISpecific () const { return Info.IsABISpecific ; }
3295
3345
};
3296
3346
3297
3347
struct RemovedDeclDiag : public DiagBase {
@@ -3513,7 +3563,9 @@ void DiagnosisEmitter::DeclTypeChangeDiag::output() const {
3513
3563
bool DiagnosisEmitter::DeclAttrDiag::operator <(DeclAttrDiag Other) const {
3514
3564
if (Kind != Other.Kind )
3515
3565
return Kind < Other.Kind ;
3516
- return DeclName.compare_lower (Other.DeclName );
3566
+ if (DeclName != Other.DeclName )
3567
+ return DeclName.compare (Other.DeclName ) < 0 ;
3568
+ return AttrAfter.compare (Other.AttrAfter ) < 0 ;
3517
3569
}
3518
3570
3519
3571
void DiagnosisEmitter::DeclAttrDiag::output () const {
@@ -3535,9 +3587,9 @@ void DiagnosisEmitter::diagnosis(NodePtr LeftRoot, NodePtr RightRoot,
3535
3587
void DiagnosisEmitter::handle (const SDKNodeDecl *Node, NodeAnnotation Anno) {
3536
3588
assert (Node->isAnnotatedAs (Anno));
3537
3589
auto &Ctx = Node->getSDKContext ();
3538
- MetaInfo ScreenInfo (Node);
3539
3590
switch (Anno) {
3540
3591
case NodeAnnotation::Removed: {
3592
+ MetaInfo ScreenInfo (Node, false );
3541
3593
// If we can find a type alias decl with the same name of this type, we
3542
3594
// consider the type is not removed.
3543
3595
if (findTypeAliasDecl (Node))
@@ -3599,6 +3651,7 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
3599
3651
return ;
3600
3652
}
3601
3653
case NodeAnnotation::Rename: {
3654
+ MetaInfo ScreenInfo (Node, false );
3602
3655
auto *Count = UpdateMap.findUpdateCounterpart (Node)->getAs <SDKNodeDecl>();
3603
3656
RenamedDecls.Diags .emplace_back (ScreenInfo,
3604
3657
Node->getDeclKind (), Count->getDeclKind (),
@@ -3607,27 +3660,31 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
3607
3660
return ;
3608
3661
}
3609
3662
case NodeAnnotation::NowMutating: {
3663
+ MetaInfo ScreenInfo (Node, false );
3610
3664
AttrChangedDecls.Diags .emplace_back (ScreenInfo,
3611
3665
Node->getDeclKind (),
3612
3666
Node->getFullyQualifiedName (),
3613
3667
Ctx.buffer (" mutating" ));
3614
3668
return ;
3615
3669
}
3616
3670
case NodeAnnotation::NowThrowing: {
3671
+ MetaInfo ScreenInfo (Node, false );
3617
3672
AttrChangedDecls.Diags .emplace_back (ScreenInfo,
3618
3673
Node->getDeclKind (),
3619
3674
Node->getFullyQualifiedName (),
3620
3675
Ctx.buffer (" throwing" ));
3621
3676
return ;
3622
3677
}
3623
3678
case NodeAnnotation::StaticChange: {
3679
+ MetaInfo ScreenInfo (Node, false );
3624
3680
AttrChangedDecls.Diags .emplace_back (ScreenInfo,
3625
3681
Node->getDeclKind (),
3626
3682
Node->getFullyQualifiedName (),
3627
3683
Ctx.buffer (Node->isStatic () ? " not static" : " static" ));
3628
3684
return ;
3629
3685
}
3630
3686
case NodeAnnotation::OwnershipChange: {
3687
+ MetaInfo ScreenInfo (Node, false );
3631
3688
auto getOwnershipDescription = [&](swift::ReferenceOwnership O) {
3632
3689
if (O == ReferenceOwnership::Strong)
3633
3690
return Ctx.buffer (" strong" );
@@ -3640,9 +3697,22 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
3640
3697
getOwnershipDescription (Count->getReferenceOwnership ()));
3641
3698
return ;
3642
3699
}
3643
- default :
3700
+ default : {
3701
+ // Diagnose the addition/removal of attributes with ABI impact.
3702
+ auto Infos = Ctx.getABIAttributeInfo ();
3703
+ auto It = std::find_if (Infos.begin (), Infos.end (),
3704
+ [&](const ABIAttributeInfo &I) { return I.Annotation == Anno; });
3705
+ if (It == Infos.end ())
3706
+ return ;
3707
+ MetaInfo ScreenInfo (Node, true );
3708
+ auto Desc = Node->hasDeclAttribute (It->Kind ) ?
3709
+ Ctx.buffer ((llvm::Twine (" without " ) + It->Content ).str ()):
3710
+ Ctx.buffer ((llvm::Twine (" with " ) + It->Content ).str ());
3711
+ AttrChangedDecls.Diags .emplace_back (ScreenInfo, Node->getDeclKind (),
3712
+ Node->getFullyQualifiedName (), Desc);
3644
3713
return ;
3645
3714
}
3715
+ }
3646
3716
}
3647
3717
3648
3718
void DiagnosisEmitter::visitDecl (SDKNodeDecl *Node) {
@@ -3692,7 +3762,7 @@ void DiagnosisEmitter::visit(NodePtr Node) {
3692
3762
}
3693
3763
}
3694
3764
3695
- typedef std::vector<NoEscapeFuncParam> NoEscapeFuncParamVector;
3765
+ typedef std::vector<NoEscapeFuncParam> NoEscapeFuncParamVector;
3696
3766
3697
3767
class NoEscapingFuncEmitter : public SDKNodeVisitor {
3698
3768
NoEscapeFuncParamVector &AllItems;
0 commit comments