From 503a9c431fb7050a1a7988d4cbc59128b56186b1 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 7 Sep 2017 17:00:38 -0700 Subject: [PATCH 1/2] [APINotes] Honor Swift 4 API notes in Swift 3 mode. More generally, change the meaning of the SwiftVersions section to be "this version or earlier" rather than "exactly this version". This keeps us from having to duplicate information for builds of Swift that support more than two possible versions (e.g. 3, 4, and 5). --- lib/APINotes/APINotesReader.cpp | 10 ++- .../Headers/VersionedKit.apinotes | 64 ++++++++++++++++- .../Headers/VersionedKit.h | 27 ++++++-- test/APINotes/versioned-multi.c | 69 +++++++++++++++++++ test/APINotes/versioned.m | 12 ++-- 5 files changed, 166 insertions(+), 16 deletions(-) create mode 100644 test/APINotes/versioned-multi.c diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp index 0b802b487e5..eddab497a6a 100644 --- a/lib/APINotes/APINotesReader.cpp +++ b/lib/APINotes/APINotesReader.cpp @@ -1492,9 +1492,13 @@ APINotesReader::VersionedInfo::VersionedInfo( Selected = Results.size(); for (unsigned i = 0, n = Results.size(); i != n; ++i) { - if (Results[i].first == version) { - Selected = i; - break; + if (version && Results[i].first >= version) { + // Pick the closest match. If the current version is "4", then entries for + // 4 are better than entries for 5, but both are valid. + if (Selected == Results.size() || + Results[Selected].first > Results[i].first) { + Selected = i; + } } if (!Results[i].first) { diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes index c02c6cbac9a..9099615a142 100644 --- a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes +++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes @@ -36,6 +36,15 @@ Tags: EnumKind: NSClosedEnum - Name: UndoAllThatHasBeenDoneToMe EnumKind: none +Typedefs: + - Name: MultiVersionedTypedef34Notes + SwiftName: MultiVersionedTypedef34Notes_NEW + - Name: MultiVersionedTypedef345Notes + SwiftName: MultiVersionedTypedef345Notes_NEW + - Name: MultiVersionedTypedef4Notes + SwiftName: MultiVersionedTypedef4Notes_NEW + - Name: MultiVersionedTypedef45Notes + SwiftName: MultiVersionedTypedef45Notes_NEW SwiftVersions: - Version: 3.0 Classes: @@ -87,6 +96,55 @@ SwiftVersions: Typedefs: - Name: MyDoubleWrapper SwiftWrapper: none - - - \ No newline at end of file + - Name: MultiVersionedTypedef34 + SwiftName: MultiVersionedTypedef34_3 + - Name: MultiVersionedTypedef34Header + SwiftName: MultiVersionedTypedef34Header_3 + - Name: MultiVersionedTypedef34Notes + SwiftName: MultiVersionedTypedef34Notes_3 + - Name: MultiVersionedTypedef345 + SwiftName: MultiVersionedTypedef345_3 + - Name: MultiVersionedTypedef345Header + SwiftName: MultiVersionedTypedef345Header_3 + - Name: MultiVersionedTypedef345Notes + SwiftName: MultiVersionedTypedef345Notes_3 + - Version: 5 + Typedefs: + - Name: MultiVersionedTypedef345 + SwiftName: MultiVersionedTypedef345_5 + - Name: MultiVersionedTypedef345Header + SwiftName: MultiVersionedTypedef345Header_5 + - Name: MultiVersionedTypedef345Notes + SwiftName: MultiVersionedTypedef345Notes_5 + - Name: MultiVersionedTypedef45 + SwiftName: MultiVersionedTypedef45_5 + - Name: MultiVersionedTypedef45Header + SwiftName: MultiVersionedTypedef45Header_5 + - Name: MultiVersionedTypedef45Notes + SwiftName: MultiVersionedTypedef45Notes_5 + - Version: 4 # Versions are deliberately ordered as "3, 5, 4" to catch bugs. + Typedefs: + - Name: MultiVersionedTypedef34 + SwiftName: MultiVersionedTypedef34_4 + - Name: MultiVersionedTypedef34Header + SwiftName: MultiVersionedTypedef34Header_4 + - Name: MultiVersionedTypedef34Notes + SwiftName: MultiVersionedTypedef34Notes_4 + - Name: MultiVersionedTypedef345 + SwiftName: MultiVersionedTypedef345_4 + - Name: MultiVersionedTypedef345Header + SwiftName: MultiVersionedTypedef345Header_4 + - Name: MultiVersionedTypedef345Notes + SwiftName: MultiVersionedTypedef345Notes_4 + - Name: MultiVersionedTypedef4 + SwiftName: MultiVersionedTypedef4_4 + - Name: MultiVersionedTypedef4Header + SwiftName: MultiVersionedTypedef4Header_4 + - Name: MultiVersionedTypedef4Notes + SwiftName: MultiVersionedTypedef4Notes_4 + - Name: MultiVersionedTypedef45 + SwiftName: MultiVersionedTypedef45_4 + - Name: MultiVersionedTypedef45Header + SwiftName: MultiVersionedTypedef45Header_4 + - Name: MultiVersionedTypedef45Notes + SwiftName: MultiVersionedTypedef45Notes_4 diff --git a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h index 61a10034503..b060c9423cd 100644 --- a/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h +++ b/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h @@ -2,6 +2,11 @@ void moveToPointDUMP(double x, double y) __attribute__((swift_name("moveTo(x:y:) void acceptClosure(void (^ __attribute__((noescape)) block)(void)); +void privateFunc(void) __attribute__((swift_private)); + +typedef double MyDoubleWrapper __attribute__((swift_wrapper(struct))); + +#if __OBJC__ @class NSString; extern NSString *MyErrorDomain; @@ -14,10 +19,6 @@ __attribute__((swift_bridge("MyValueType"))) @interface MyReferenceType @end -void privateFunc(void) __attribute__((swift_private)); - -typedef double MyDoubleWrapper __attribute__((swift_wrapper(struct))); - @interface TestProperties @property (nonatomic, readwrite, retain) id accessorsOnly; @property (nonatomic, readwrite, retain, class) id accessorsOnlyForClass; @@ -42,6 +43,7 @@ typedef double MyDoubleWrapper __attribute__((swift_wrapper(struct))); __attribute__((swift_name("Swift4Name"))) @interface Swift3RenamedAlsoDUMP @end +#endif enum __attribute__((flag_enum)) FlagEnum { @@ -110,3 +112,20 @@ enum SoonToBeNSClosedEnum { enum UndoAllThatHasBeenDoneToMe { UndoAllThatHasBeenDoneToMeA = 1 } __attribute__((flag_enum)) __attribute__((enum_extensibility(closed))); + + +typedef int MultiVersionedTypedef4; +typedef int MultiVersionedTypedef4Notes; +typedef int MultiVersionedTypedef4Header __attribute__((swift_name("MultiVersionedTypedef4Header_NEW"))); + +typedef int MultiVersionedTypedef34; +typedef int MultiVersionedTypedef34Notes; +typedef int MultiVersionedTypedef34Header __attribute__((swift_name("MultiVersionedTypedef34Header_NEW"))); + +typedef int MultiVersionedTypedef45; +typedef int MultiVersionedTypedef45Notes; +typedef int MultiVersionedTypedef45Header __attribute__((swift_name("MultiVersionedTypedef45Header_NEW"))); + +typedef int MultiVersionedTypedef345; +typedef int MultiVersionedTypedef345Notes; +typedef int MultiVersionedTypedef345Header __attribute__((swift_name("MultiVersionedTypedef345Header_NEW"))); diff --git a/test/APINotes/versioned-multi.c b/test/APINotes/versioned-multi.c new file mode 100644 index 00000000000..48c51fd932e --- /dev/null +++ b/test/APINotes/versioned-multi.c @@ -0,0 +1,69 @@ +// RUN: rm -rf %t && mkdir -p %t + +// Build and check the unversioned module file. +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Unversioned -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s +// RUN: %clang_cc1 -ast-print %t/ModulesCache/Unversioned/VersionedKit.pcm | FileCheck -check-prefix=CHECK-UNVERSIONED %s + +// Build and check the various versions. +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Versioned3 -fdisable-module-hash -fapinotes-modules -fapinotes-swift-version=3 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s +// RUN: %clang_cc1 -ast-print %t/ModulesCache/Versioned3/VersionedKit.pcm | FileCheck -check-prefix=CHECK-VERSIONED-3 %s + +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Versioned4 -fdisable-module-hash -fapinotes-modules -fapinotes-swift-version=4 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s +// RUN: %clang_cc1 -ast-print %t/ModulesCache/Versioned4/VersionedKit.pcm | FileCheck -check-prefix=CHECK-VERSIONED-4 %s + +// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/Versioned5 -fdisable-module-hash -fapinotes-modules -fapinotes-swift-version=5 -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s +// RUN: %clang_cc1 -ast-print %t/ModulesCache/Versioned5/VersionedKit.pcm | FileCheck -check-prefix=CHECK-VERSIONED-5 %s + +#import + +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef4; +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef4Notes __attribute__((swift_name("MultiVersionedTypedef4Notes_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef4Header __attribute__((swift_name("MultiVersionedTypedef4Header_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef34; +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef34Notes __attribute__((swift_name("MultiVersionedTypedef34Notes_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef34Header __attribute__((swift_name("MultiVersionedTypedef34Header_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef45; +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef45Notes __attribute__((swift_name("MultiVersionedTypedef45Notes_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef45Header __attribute__((swift_name("MultiVersionedTypedef45Header_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef345; +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef345Notes __attribute__((swift_name("MultiVersionedTypedef345Notes_NEW"))); +// CHECK-UNVERSIONED: typedef int MultiVersionedTypedef345Header __attribute__((swift_name("MultiVersionedTypedef345Header_NEW"))); + +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef4 __attribute__((swift_name("MultiVersionedTypedef4_4"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef4Notes __attribute__((swift_name("MultiVersionedTypedef4Notes_4"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef4Header __attribute__((swift_name("MultiVersionedTypedef4Header_4"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef34 __attribute__((swift_name("MultiVersionedTypedef34_3"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef34Notes __attribute__((swift_name("MultiVersionedTypedef34Notes_3"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef34Header __attribute__((swift_name("MultiVersionedTypedef34Header_3"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef45 __attribute__((swift_name("MultiVersionedTypedef45_4"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef45Notes __attribute__((swift_name("MultiVersionedTypedef45Notes_4"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef45Header __attribute__((swift_name("MultiVersionedTypedef45Header_4"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef345 __attribute__((swift_name("MultiVersionedTypedef345_3"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef345Notes __attribute__((swift_name("MultiVersionedTypedef345Notes_3"))); +// CHECK-VERSIONED-3: typedef int MultiVersionedTypedef345Header __attribute__((swift_name("MultiVersionedTypedef345Header_3"))); + +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef4 __attribute__((swift_name("MultiVersionedTypedef4_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef4Notes __attribute__((swift_name("MultiVersionedTypedef4Notes_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef4Header __attribute__((swift_name("MultiVersionedTypedef4Header_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef34 __attribute__((swift_name("MultiVersionedTypedef34_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef34Notes __attribute__((swift_name("MultiVersionedTypedef34Notes_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef34Header __attribute__((swift_name("MultiVersionedTypedef34Header_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef45 __attribute__((swift_name("MultiVersionedTypedef45_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef45Notes __attribute__((swift_name("MultiVersionedTypedef45Notes_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef45Header __attribute__((swift_name("MultiVersionedTypedef45Header_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef345 __attribute__((swift_name("MultiVersionedTypedef345_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef345Notes __attribute__((swift_name("MultiVersionedTypedef345Notes_4"))); +// CHECK-VERSIONED-4: typedef int MultiVersionedTypedef345Header __attribute__((swift_name("MultiVersionedTypedef345Header_4"))); + +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef4; +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef4Notes __attribute__((swift_name("MultiVersionedTypedef4Notes_NEW"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef4Header __attribute__((swift_name("MultiVersionedTypedef4Header_NEW"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef34; +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef34Notes __attribute__((swift_name("MultiVersionedTypedef34Notes_NEW"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef34Header __attribute__((swift_name("MultiVersionedTypedef34Header_NEW"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef45 __attribute__((swift_name("MultiVersionedTypedef45_5"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef45Notes __attribute__((swift_name("MultiVersionedTypedef45Notes_5"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef45Header __attribute__((swift_name("MultiVersionedTypedef45Header_5"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef345 __attribute__((swift_name("MultiVersionedTypedef345_5"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef345Notes __attribute__((swift_name("MultiVersionedTypedef345Notes_5"))); +// CHECK-VERSIONED-5: typedef int MultiVersionedTypedef345Header __attribute__((swift_name("MultiVersionedTypedef345Header_5"))); diff --git a/test/APINotes/versioned.m b/test/APINotes/versioned.m index 2f85735b7cc..905a9c7eb8a 100644 --- a/test/APINotes/versioned.m +++ b/test/APINotes/versioned.m @@ -53,6 +53,10 @@ // CHECK-UNVERSIONED: void acceptClosure(void (^block)(void) __attribute__((noescape))); // CHECK-VERSIONED: void acceptClosure(void (^block)(void)); +// CHECK-UNVERSIONED: void privateFunc() __attribute__((swift_private)); + +// CHECK-UNVERSIONED: typedef double MyDoubleWrapper __attribute__((swift_wrapper("struct"))); + // CHECK-UNVERSIONED: enum MyErrorCode { // CHECK-UNVERSIONED-NEXT: MyErrorCodeFailed = 1 // CHECK-UNVERSIONED-NEXT: } __attribute__((ns_error_domain(MyErrorDomain))); @@ -60,9 +64,9 @@ // CHECK-UNVERSIONED: __attribute__((swift_bridge("MyValueType"))) // CHECK-UNVERSIONED: @interface MyReferenceType -// CHECK-UNVERSIONED: void privateFunc() __attribute__((swift_private)); +// CHECK-VERSIONED: void privateFunc(); -// CHECK-UNVERSIONED: typedef double MyDoubleWrapper __attribute__((swift_wrapper("struct"))); +// CHECK-VERSIONED: typedef double MyDoubleWrapper; // CHECK-VERSIONED: enum MyErrorCode { // CHECK-VERSIONED-NEXT: MyErrorCodeFailed = 1 @@ -71,10 +75,6 @@ // CHECK-VERSIONED-NOT: __attribute__((swift_bridge("MyValueType"))) // CHECK-VERSIONED: @interface MyReferenceType -// CHECK-VERSIONED: void privateFunc(); - -// CHECK-VERSIONED: typedef double MyDoubleWrapper; - // CHECK-UNVERSIONED: __attribute__((swift_objc_members) // CHECK-UNVERSIONED-NEXT: @interface TestProperties // CHECK-VERSIONED-NOT: __attribute__((swift_objc_members) From 202145d8d243e094e0d832c90d085672a185b083 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 7 Sep 2017 17:27:34 -0700 Subject: [PATCH 2/2] [APINotes] Sort versioned info entries to make lookup easier. No functionality change. --- lib/APINotes/APINotesReader.cpp | 35 ++++++++++++++++----------------- lib/APINotes/APINotesWriter.cpp | 10 ++++++++-- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp index eddab497a6a..a5dd24d3300 100644 --- a/lib/APINotes/APINotesReader.cpp +++ b/lib/APINotes/APINotesReader.cpp @@ -1487,31 +1487,30 @@ APINotesReader::VersionedInfo::VersionedInfo( SmallVector, 1> results) : Results(std::move(results)) { - // Look for an exact version match. - Optional unversioned; - Selected = Results.size(); + assert(!Results.empty()); + assert(std::is_sorted(Results.begin(), Results.end(), + [](const std::pair &left, + const std::pair &right) -> bool { + assert(left.first != right.first && "two entries for the same version"); + return left.first < right.first; + })); + Selected = Results.size(); for (unsigned i = 0, n = Results.size(); i != n; ++i) { if (version && Results[i].first >= version) { - // Pick the closest match. If the current version is "4", then entries for - // 4 are better than entries for 5, but both are valid. - if (Selected == Results.size() || - Results[Selected].first > Results[i].first) { - Selected = i; - } - } - - if (!Results[i].first) { - assert(!unversioned && "Two unversioned entries?"); - unversioned = i; + // If the current version is "4", then entries for 4 are better than + // entries for 5, but both are valid. Because entries are sorted, we get + // that behavior by picking the first match. + Selected = i; + break; } } // If we didn't find a match but we have an unversioned result, use the - // unversioned result. - if (Selected == Results.size() && unversioned) { - Selected = *unversioned; - } + // unversioned result. This will always be the first entry because we encode + // it as version 0. + if (Selected == Results.size() && Results[0].first.empty()) + Selected = 0; } auto APINotesReader::lookupObjCClassID(StringRef name) -> Optional { diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp index 285a35efe20..b178e257e70 100644 --- a/lib/APINotes/APINotesWriter.cpp +++ b/lib/APINotes/APINotesWriter.cpp @@ -475,10 +475,16 @@ namespace { template void emitVersionedInfo( raw_ostream &out, - const SmallVectorImpl> &infoArray, + SmallVectorImpl> &infoArray, llvm::function_ref::Type& info)> emitInfo) { + std::sort(infoArray.begin(), infoArray.end(), + [](const std::pair &left, + const std::pair &right) -> bool { + assert(left.first != right.first && "two entries for the same version"); + return left.first < right.first; + }); endian::Writer writer(out); writer.write(infoArray.size()); for (const auto &element : infoArray) { @@ -528,7 +534,7 @@ namespace { using key_type_ref = key_type; using data_type = SmallVector, 1>; - using data_type_ref = const data_type &; + using data_type_ref = data_type &; using hash_value_type = size_t; using offset_type = unsigned;