diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index dcafc838548..63368868326 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -1746,7 +1746,8 @@ def SwiftVersioned : Attr { // This attribute has no spellings as it is only ever created implicitly // from API notes. let Spellings = []; - let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">]; + let Args = [VersionArgument<"Version">, AttrArgument<"AttrToAdd">, + BoolArgument<"IsReplacedByActive">]; let SemaHandler = 0; let Documentation = [Undocumented]; } @@ -1755,7 +1756,8 @@ def SwiftVersionedRemoval : Attr { // This attribute has no spellings as it is only ever created implicitly // from API notes. let Spellings = []; - let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">]; + let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, + BoolArgument<"IsReplacedByActive">]; let SemaHandler = 0; let Documentation = [Undocumented]; let AdditionalMembers = [{ diff --git a/lib/Sema/SemaAPINotes.cpp b/lib/Sema/SemaAPINotes.cpp index 6145fef3de2..0b3cdbb9603 100644 --- a/lib/Sema/SemaAPINotes.cpp +++ b/lib/Sema/SemaAPINotes.cpp @@ -21,14 +21,21 @@ namespace { IsNotActive, IsActive }; + enum IsReplacement_t : bool { + IsNotReplacement, + IsReplacement + }; struct VersionedInfoMetadata { /// An empty version refers to unversioned metadata. VersionTuple Version; - bool IsActive; + unsigned IsActive: 1; + unsigned IsReplacement: 1; - VersionedInfoMetadata(VersionTuple version, IsActive_t active) - : Version(version), IsActive(active == IsActive_t::IsActive) {} + VersionedInfoMetadata(VersionTuple version, IsActive_t active, + IsReplacement_t replacement) + : Version(version), IsActive(active == IsActive_t::IsActive), + IsReplacement(replacement == IsReplacement_t::IsReplacement) {} }; } // end anonymous namespace @@ -148,9 +155,8 @@ namespace { if (existing != end) { // Remove the existing attribute, and treat it as a superseded // non-versioned attribute. - auto *versioned = - SwiftVersionedAttr::CreateImplicit(S.Context, clang::VersionTuple(), - *existing); + auto *versioned = SwiftVersionedAttr::CreateImplicit( + S.Context, metadata.Version, *existing, /*IsReplacedByActive*/true); D->getAttrs().erase(existing.getCurrent()); D->addAttr(versioned); @@ -166,19 +172,18 @@ namespace { } else { if (shouldAddAttribute) { if (auto attr = createAttr()) { - auto *versioned = - SwiftVersionedAttr::CreateImplicit(S.Context, metadata.Version, - attr); + auto *versioned = SwiftVersionedAttr::CreateImplicit( + S.Context, metadata.Version, attr, + /*IsReplacedByActive*/metadata.IsReplacement); D->addAttr(versioned); } } else { // FIXME: This isn't preserving enough information for things like // availability, where we're trying to remove a /specific/ kind of // attribute. - auto *versioned = - SwiftVersionedRemovalAttr::CreateImplicit(S.Context, - metadata.Version, - AttrKindFor::value); + auto *versioned = SwiftVersionedRemovalAttr::CreateImplicit( + S.Context, metadata.Version, AttrKindFor::value, + /*IsReplacedByActive*/metadata.IsReplacement); D->addAttr(versioned); } } @@ -684,7 +689,8 @@ static void maybeAttachUnversionedSwiftName( } // Then explicitly call that out with a removal attribute. - VersionedInfoMetadata DummyFutureMetadata(VersionTuple(), IsNotActive); + VersionedInfoMetadata DummyFutureMetadata(SelectedVersion, IsNotActive, + IsReplacement); handleAPINotedAttribute(S, D, /*add*/false, DummyFutureMetadata, []() -> SwiftNameAttr * { @@ -709,7 +715,13 @@ static void ProcessVersionedAPINotes( for (unsigned i = 0, e = Info.size(); i != e; ++i) { std::tie(Version, InfoSlice) = Info[i]; auto Active = (i == Selected) ? IsActive : IsNotActive; - ProcessAPINotes(S, D, InfoSlice, VersionedInfoMetadata(Version, Active)); + auto Replacement = IsNotReplacement; + if (Active == IsNotActive && Version.empty()) { + Replacement = IsReplacement; + Version = Info[Selected].first; + } + ProcessAPINotes(S, D, InfoSlice, VersionedInfoMetadata(Version, Active, + Replacement)); } } diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes index 9099615a142..572c714b3d6 100644 --- a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes +++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes @@ -15,6 +15,9 @@ Classes: - Name: accessorsOnlyForClassExceptInVersion3 PropertyKind: Class SwiftImportAsAccessors: true +Functions: + - Name: unversionedRenameDUMP + SwiftName: 'unversionedRename_NOTES()' Tags: - Name: APINotedFlagEnum FlagEnum: true @@ -123,6 +126,9 @@ SwiftVersions: - Name: MultiVersionedTypedef45Notes SwiftName: MultiVersionedTypedef45Notes_5 - Version: 4 # Versions are deliberately ordered as "3, 5, 4" to catch bugs. + Classes: + - Name: Swift4RenamedDUMP + SwiftName: SpecialSwift4Name Typedefs: - Name: MultiVersionedTypedef34 SwiftName: MultiVersionedTypedef34_4 diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h index b060c9423cd..9ce95633c52 100644 --- a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h +++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h @@ -1,5 +1,7 @@ void moveToPointDUMP(double x, double y) __attribute__((swift_name("moveTo(x:y:)"))); +void unversionedRenameDUMP(void) __attribute__((swift_name("unversionedRename_HEADER()"))); + void acceptClosure(void (^ __attribute__((noescape)) block)(void)); void privateFunc(void) __attribute__((swift_private)); @@ -43,6 +45,10 @@ __attribute__((swift_bridge("MyValueType"))) __attribute__((swift_name("Swift4Name"))) @interface Swift3RenamedAlsoDUMP @end + +@interface Swift4RenamedDUMP +@end + #endif diff --git a/test/APINotes/properties.m b/test/APINotes/properties.m index fe3c7384044..0b3d24482c0 100644 --- a/test/APINotes/properties.m +++ b/test/APINotes/properties.m @@ -18,25 +18,25 @@ // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyInVersion3 'id' // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit -// CHECK-4-NEXT: SwiftVersionedAttr {{.+}} 3.0 +// CHECK-4-NEXT: SwiftVersionedAttr {{.+}} 3.0{{$}} // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit // CHECK-NOT: Attr // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClassInVersion3 'id' // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit -// CHECK-4-NEXT: SwiftVersionedAttr {{.+}} 3.0 +// CHECK-4-NEXT: SwiftVersionedAttr {{.+}} 3.0{{$}} // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit // CHECK-NOT: Attr // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyExceptInVersion3 'id' -// CHECK-3-NEXT: SwiftVersionedAttr {{.+}} 0{{$}} +// CHECK-3-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit // CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} // CHECK-NOT: Attr // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClassExceptInVersion3 'id' -// CHECK-3-NEXT: SwiftVersionedAttr {{.+}} 0{{$}} +// CHECK-3-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} Implicit // CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} diff --git a/test/APINotes/versioned.m b/test/APINotes/versioned.m index 905a9c7eb8a..e7ec2eb4337 100644 --- a/test/APINotes/versioned.m +++ b/test/APINotes/versioned.m @@ -16,38 +16,53 @@ // CHECK-VERSIONED: void moveToPointDUMP(double x, double y) __attribute__((swift_name("moveTo(a:b:)"))); // CHECK-DUMP-LABEL: Dumping moveToPointDUMP -// CHECK-VERSIONED-DUMP: SwiftVersionedAttr {{.+}} Implicit 0 +// CHECK-VERSIONED-DUMP: SwiftVersionedAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "moveTo(x:y:)" // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "moveTo(a:b:)" // CHECK-UNVERSIONED-DUMP: SwiftNameAttr {{.+}} "moveTo(x:y:)" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0 +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "moveTo(a:b:)" // CHECK-DUMP-NOT: Attr +// CHECK-DUMP-LABEL: Dumping unversionedRenameDUMP +// CHECK-DUMP: in VersionedKit unversionedRenameDUMP +// CHECK-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 0 IsReplacedByActive{{$}} +// CHECK-DUMP-NEXT: SwiftNameAttr {{.+}} "unversionedRename_HEADER()" +// CHECK-DUMP-NEXT: SwiftNameAttr {{.+}} "unversionedRename_NOTES()" +// CHECK-DUMP-NOT: Attr + // CHECK-DUMP-LABEL: Dumping TestGenericDUMP // CHECK-VERSIONED-DUMP: SwiftImportAsNonGenericAttr {{.+}} Implicit -// CHECK-UNVERSIONED-DUMP: SwiftVersionedAttr {{.+}} Implicit 3.0 +// CHECK-UNVERSIONED-DUMP: SwiftVersionedAttr {{.+}} Implicit 3.0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftImportAsNonGenericAttr {{.+}} Implicit // CHECK-DUMP-NOT: Attr // CHECK-DUMP-LABEL: Dumping Swift3RenamedOnlyDUMP // CHECK-DUMP: in VersionedKit Swift3RenamedOnlyDUMP -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 0 {{[0-9]+}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} IsReplacedByActive{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift3Name" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0 +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "SpecialSwift3Name" // CHECK-DUMP-NOT: Attr // CHECK-DUMP-LABEL: Dumping Swift3RenamedAlsoDUMP // CHECK-DUMP: in VersionedKit Swift3RenamedAlsoDUMP -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 0 +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "Swift4Name" // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift3Also" // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "Swift4Name" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0 +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 3.0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "SpecialSwift3Also" // CHECK-DUMP-NOT: Attr +// CHECK-DUMP-LABEL: Dumping Swift4RenamedDUMP +// CHECK-DUMP: in VersionedKit Swift4RenamedDUMP +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 4 {{[0-9]+}} IsReplacedByActive{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift4Name" +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAttr {{.+}} Implicit 4{{$}} +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} Implicit "SpecialSwift4Name" +// CHECK-DUMP-NOT: Attr + // CHECK-DUMP-NOT: Dumping // CHECK-UNVERSIONED: void acceptClosure(void (^block)(void) __attribute__((noescape)));