https://github.com/artemcm updated https://github.com/llvm/llvm-project/pull/224860
>From 78a810a3fa279de0fae83e09f06f9772c1b05814 Mon Sep 17 00:00:00 2001 From: Artem Chikin <[email protected]> Date: Sat, 19 Sep 2026 20:36:35 +0100 Subject: [PATCH] [APINotes][Unversioned] Capture presence of versioned slices separately, and track distinct slice groups In addition to aggregating attributes with `SwiftVersionedAdditionAttr` and `SwiftVersionedDeletionAttr`, we may need to also capture that an APINotes file contained a versioned slice which may not have captured any keyed attributes. For example: ``` Name: Bar Functions: - Name: foo SwiftName: 'fooBase()' # unversioned SwiftVersions: - Version: 4 Functions: - Name: foo SwiftName: 'fooFour()' # the 4.0 slice - Version: 5 Functions: - Name: foo SwiftPrivate: true # the 5.0 slice ``` When picking which attributes/notes to apply, the algorithm is to select from the lowest version slice at or above the client requested one, or the unversioned slice otherwise. Suppose we have a client at version 3. In this case, the client will have reconstructed the attributes as 3 options: - Unversioned: SwiftNameAttr "fooBase()" - 4.0: SwiftNameAttr "fooFour()" - 5.0: SwiftPrivateAttr According to the algorithm, slice 4 would win, so `foo` would get a name `fooFour()` and **not** be private. Now suppose there is instead a versioned slice which carries no keyed attributes: ``` SwiftVersions: - Version: 4 Functions: - Name: foo # declared, no keys ``` With this slice, the client would have reconstructed just two versioned-attribute options: - Unversioned: SwiftNameAttr "fooBase()" - 5.0: SwiftPrivateAttr And according to the algorithm selected 5 and marked `foo` as private. This is incorrect because the presence of the 4.0 slice still means that it is the one that must be selected for this declaration. This change adds a new (no spelling) attribute called `SwiftVersionedSliceAttr` to capture existence of all versioned slices, which the clients will then use to know which slice version to select for a given declaration. The slices a client must choose between are the ones a single lookup produced, not the ones a single APINotes reader supplied. Sema runs the selection above once per lookup and applies every winner, and there can be more than one lookup for the same declaration against the same reader. A global function with a `Where:` parameter selector gets two: the broad lookup, and the exact one. ``` Name: Bar Functions: - Name: overloaded SwiftName: 'broadBase()' # the broad lookup, unversioned - Name: overloaded Where: Parameters: - int SwiftName: 'exactBase(_:)' # the exact lookup, unversioned SwiftVersions: - Version: 4 Functions: - Name: overloaded SwiftName: 'broadFour()' # the broad lookup, 4.0 slice ``` Each lookup selects its own winner and both are applied, so a client at version 3 must end up with `broadFour()` from the broad lookup and `exactBase(_:)` from the exact one. If the two lookups were labelled with the reader they share, the client would instead reconstruct one competition: - Unversioned: SwiftNameAttr "broadBase()" - Unversioned: SwiftNameAttr "exactBase(_:)" - 4.0: SwiftNameAttr "broadFour()" and select a single winner, dropping one of the two lookups entirely. So the attributes carry a slice group rather than a reader index. One group is one lookup: a second reader is a different lookup, and so is an exact parameter-selector query beside a broad one. The value is an opaque ordinal, and only equality within one declaration means anything. --- clang/include/clang/Basic/Attr.td | 32 ++++- clang/lib/Sema/SemaAPINotes.cpp | 130 +++++++++++------- .../Headers/VersionedKit.apinotes | 4 + .../Headers/VersionedKit.h | 2 + .../APINotes/Inputs/Headers/ExportAs.apinotes | 7 + .../Inputs/Headers/ExportAsCore.apinotes | 9 ++ .../APINotes/Inputs/Headers/ExportAsCore.h | 5 + .../Inputs/Headers/SliceGroupsExact.apinotes | 19 +++ .../Inputs/Headers/SliceGroupsExact.h | 3 + .../APINotes/Inputs/Headers/module.modulemap | 4 + clang/test/APINotes/properties.m | 12 +- clang/test/APINotes/slice-groups-exact.c | 39 ++++++ clang/test/APINotes/slice-groups.c | 39 ++++++ .../APINotes/versioned-version-independent.m | 36 ++++- clang/test/APINotes/versioned.m | 34 +++-- 15 files changed, 304 insertions(+), 71 deletions(-) create mode 100644 clang/test/APINotes/Inputs/Headers/ExportAsCore.apinotes create mode 100644 clang/test/APINotes/Inputs/Headers/SliceGroupsExact.apinotes create mode 100644 clang/test/APINotes/Inputs/Headers/SliceGroupsExact.h create mode 100644 clang/test/APINotes/slice-groups-exact.c create mode 100644 clang/test/APINotes/slice-groups.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 61ef3fb612440..96d2d12d9d239 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3304,9 +3304,12 @@ def SwiftPrivate : InheritableAttr { def SwiftVersionedAddition : Attr { // This attribute has no spellings as it is only ever created implicitly // from API notes. + // + // SliceGroup says which competition this slice belongs to. let Spellings = []; let Args = [VersionArgument<"Version">, WrappedAttr<"AdditionalAttr">, - BoolArgument<"IsReplacedByActive">]; + BoolArgument<"IsReplacedByActive">, + UnsignedArgument<"SliceGroup">]; let SemaHandler = 0; let Documentation = [InternalOnly]; } @@ -3314,9 +3317,12 @@ def SwiftVersionedAddition : Attr { def SwiftVersionedRemoval : Attr { // This attribute has no spellings as it is only ever created implicitly // from API notes. + // + // SliceGroup says which competition this slice belongs to. let Spellings = []; let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">, - BoolArgument<"IsReplacedByActive">]; + BoolArgument<"IsReplacedByActive">, + UnsignedArgument<"SliceGroup">]; let SemaHandler = 0; let Documentation = [InternalOnly]; let AdditionalMembers = [{ @@ -3326,6 +3332,28 @@ def SwiftVersionedRemoval : Attr { }]; } +def SwiftVersionedSlice : Attr { + // This attribute has no spellings as it is only ever created implicitly + // from API notes, and only under -fswift-version-independent-apinotes. + // + // One of these records each Swift version slice an API notes lookup supplied + // for the declaration, whether or not that slice set any keyed values. + // A slice that sets no key still takes part in version selection, selecting it + // suppresses the annotations of every other slice in its group, so a + // consumer that recomputes the selection has to know the slice exists. + // + // SliceGroup says which slices are rivals. Clang runs version selection once + // per lookup and applies every winner, so slices from different lookups are + // in different competitions and a consumer must not pool them. One group is + // one lookup. A second API notes reader is a different lookup, and so is a + // second lookup against the same reader, such as an exact parameter-selector + // query beside a broad one. + let Spellings = []; + let Args = [VersionArgument<"Version">, UnsignedArgument<"SliceGroup">]; + let SemaHandler = 0; + let Documentation = [InternalOnly]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs]; diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 4c7e5ea16cfd7..c577b21cfb036 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -23,6 +23,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/SemaSwift.h" +#include "llvm/ADT/STLExtras.h" #include <stack> using namespace clang; @@ -34,12 +35,17 @@ enum class IsSubstitution_t : bool { Original, Replacement }; struct VersionedInfoMetadata { /// An empty version refers to unversioned metadata. VersionTuple Version; + /// Which API notes reader supplied this slice. Version selection runs + /// independently per reader, so a consumer that recomputes the selection has + /// to group slices by this index rather than pooling them. + unsigned SliceGroup; unsigned IsActive : 1; unsigned IsReplacement : 1; - VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, - IsSubstitution_t Replacement) - : Version(Version), IsActive(Active == IsActive_t::Active), + VersionedInfoMetadata(VersionTuple Version, unsigned SliceGroup, + IsActive_t Active, IsSubstitution_t Replacement) + : Version(Version), SliceGroup(SliceGroup), + IsActive(Active == IsActive_t::Active), IsReplacement(Replacement == IsSubstitution_t::Replacement) {} }; } // end anonymous namespace @@ -65,7 +71,8 @@ static void applyAPINotesType(Sema &S, Decl *decl, StringRef typeString, if (S.captureSwiftVersionIndependentAPINotes()) { auto *typeAttr = SwiftTypeAttr::CreateImplicit(S.Context, typeString); auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit( - S.Context, metadata.Version, typeAttr, metadata.IsReplacement); + S.Context, metadata.Version, typeAttr, metadata.IsReplacement, + metadata.SliceGroup); decl->addAttr(versioned); } else { if (!metadata.IsActive) @@ -98,7 +105,8 @@ static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability, auto *nullabilityAttr = SwiftNullabilityAttr::CreateImplicit(S.Context, attrNullabilityKind); auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit( - S.Context, metadata.Version, nullabilityAttr, metadata.IsReplacement); + S.Context, metadata.Version, nullabilityAttr, metadata.IsReplacement, + metadata.SliceGroup); decl->addAttr(versioned); return; } else { @@ -149,7 +157,8 @@ void handleAPINotedAttribute( // Remove the existing attribute, and treat it as a superseded // non-versioned attribute. auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit( - S.Context, Metadata.Version, *Existing, /*IsReplacedByActive*/ true); + S.Context, Metadata.Version, *Existing, /*IsReplacedByActive*/ true, + Metadata.SliceGroup); D->getAttrs().erase(Existing); D->addAttr(Versioned); @@ -167,7 +176,7 @@ void handleAPINotedAttribute( if (auto Attr = CreateAttr()) { auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit( S.Context, Metadata.Version, Attr, - /*IsReplacedByActive*/ Metadata.IsReplacement); + /*IsReplacedByActive*/ Metadata.IsReplacement, Metadata.SliceGroup); D->addAttr(Versioned); } } else { @@ -176,7 +185,7 @@ void handleAPINotedAttribute( // attribute. auto *Versioned = SwiftVersionedRemovalAttr::CreateImplicit( S.Context, Metadata.Version, AttrKindFor<A>::value, - /*IsReplacedByActive*/ Metadata.IsReplacement); + /*IsReplacedByActive*/ Metadata.IsReplacement, Metadata.SliceGroup); D->addAttr(Versioned); } } @@ -872,7 +881,8 @@ static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D, template <typename SpecificInfo> static void maybeAttachUnversionedSwiftName( Sema &S, Decl *D, - const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { + const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info, + unsigned SliceGroup) { if (D->hasAttr<SwiftNameAttr>()) return; if (!Info.getSelected()) @@ -896,8 +906,9 @@ static void maybeAttachUnversionedSwiftName( } // Then explicitly call that out with a removal attribute. - VersionedInfoMetadata DummyFutureMetadata( - SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement); + VersionedInfoMetadata DummyFutureMetadata(SelectedVersion, SliceGroup, + IsActive_t::Inactive, + IsSubstitution_t::Replacement); handleAPINotedAttribute<SwiftNameAttr>( S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * { llvm_unreachable("should not try to add an attribute here"); @@ -907,13 +918,17 @@ static void maybeAttachUnversionedSwiftName( /// Processes all versions of versioned API notes. /// /// Just dispatches to the various ProcessAPINotes functions in this file. +/// +/// \param SliceGroup Which API notes reader supplied \p Info. Selection runs +/// independently per reader, so this has to travel with every slice. template <typename SpecificDecl, typename SpecificInfo> static void ProcessVersionedAPINotes( Sema &S, SpecificDecl *D, - const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { + const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info, + unsigned SliceGroup) { if (!S.captureSwiftVersionIndependentAPINotes()) - maybeAttachUnversionedSwiftName(S, D, Info); + maybeAttachUnversionedSwiftName(S, D, Info, SliceGroup); unsigned Selected = Info.getSelected().value_or(Info.size()); @@ -929,14 +944,22 @@ static void ProcessVersionedAPINotes( // right one. if (S.captureSwiftVersionIndependentAPINotes()) { Active = IsActive_t::Inactive; - Replacement = IsSubstitution_t::Original; + + // Record that this slice exists, independently of whether it goes on to + // set any key. A slice that sets nothing still wins selection for the + // versions it covers, and winning suppresses every other slice, so a + // client recomputing the selection cannot infer the slice set from the + // addition and removal wrappers alone. + D->addAttr(SwiftVersionedSliceAttr::CreateImplicit(S.Context, Version, + SliceGroup)); } else if (Active == IsActive_t::Inactive && Version.empty()) { Replacement = IsSubstitution_t::Replacement; Version = Info[Selected].first; } - ProcessAPINotes(S, D, InfoSlice, - VersionedInfoMetadata(Version, Active, Replacement)); + ProcessAPINotes( + S, D, InfoSlice, + VersionedInfoMetadata(Version, SliceGroup, Active, Replacement)); } } @@ -1109,22 +1132,29 @@ void APINotesSelectorDiagnosticReaderState::markCandidatesUsed( } } -// Apply the first exact selector entry found. This preserves source-spelling -// precedence over the desugared fallback and avoids applying multiple exact -// entries for the same declaration. +/// Apply the first exact selector entry found. This preserves source-spelling +/// precedence over the desugared fallback and avoids applying multiple exact +/// entries for the same declaration. +/// +/// \param SliceGroup Which competition the slices from \p LookupExact belong +/// to. This lookup runs its own version selection, so it is a competition +/// distinct from the broad lookup beside it even though both read the same +/// reader, and the caller must pass a group that no other lookup for this +/// declaration uses. See the SwiftVersionedSlice comment in Attr.td. template <typename SpecificInfo, typename SpecificDecl> static void processExactAPINotes( Sema &S, SpecificDecl *D, const APINotesParameterSelectorCandidates &ParameterSelectorCandidates, llvm::function_ref<api_notes::APINotesReader::VersionedInfo<SpecificInfo>( ArrayRef<std::string>)> - LookupExact) { + LookupExact, + unsigned SliceGroup) { auto ProcessSelector = [&](const APINotesParameterSelector &Selector) { auto Info = LookupExact(Selector.Parameters); if (Info.size() == 0) return false; - ProcessVersionedAPINotes(S, D, Info); + ProcessVersionedAPINotes(S, D, Info, SliceGroup); return true; }; @@ -1154,10 +1184,10 @@ void Sema::ProcessAPINotes(Decl *D) { UnwindNamespaceContext(DC, APINotes); // Global variables. if (auto VD = dyn_cast<VarDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { auto Info = Reader->lookupGlobalVariable(VD->getName(), APINotesContext); - ProcessVersionedAPINotes(*this, VD, Info); + ProcessVersionedAPINotes(*this, VD, Info, SliceGroup); } return; @@ -1169,10 +1199,10 @@ void Sema::ProcessAPINotes(Decl *D) { auto ParameterSelectorCandidates = getAPINotesParameterSelectorCandidates(*this, FD); - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { auto Info = Reader->lookupGlobalFunction(FD->getName(), APINotesContext); - ProcessVersionedAPINotes(*this, FD, Info); + ProcessVersionedAPINotes(*this, FD, Info, SliceGroup); if (ParameterSelectorCandidates) processExactAPINotes<api_notes::GlobalFunctionInfo>( @@ -1180,7 +1210,9 @@ void Sema::ProcessAPINotes(Decl *D) { [&](ArrayRef<std::string> Parameters) { return Reader->lookupGlobalFunction(FD->getName(), Parameters, APINotesContext); - }); + }, + // A second competition against the same reader. + Readers.size() + SliceGroup); if (ParameterSelectorCandidates) { auto &DiagnosticState = @@ -1204,9 +1236,9 @@ void Sema::ProcessAPINotes(Decl *D) { // Objective-C classes. if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { auto Info = Reader->lookupObjCClassInfo(Class->getName()); - ProcessVersionedAPINotes(*this, Class, Info); + ProcessVersionedAPINotes(*this, Class, Info, SliceGroup); } return; @@ -1214,9 +1246,9 @@ void Sema::ProcessAPINotes(Decl *D) { // Objective-C protocols. if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName()); - ProcessVersionedAPINotes(*this, Protocol, Info); + ProcessVersionedAPINotes(*this, Protocol, Info, SliceGroup); } return; @@ -1256,11 +1288,11 @@ void Sema::ProcessAPINotes(Decl *D) { T.split(), getASTContext().getPrintingPolicy()); } - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { if (auto ParentTag = dyn_cast<TagDecl>(Tag->getDeclContext())) APINotesContext = UnwindTagContext(ParentTag, APINotes); auto Info = Reader->lookupTag(LookupName, APINotesContext); - ProcessVersionedAPINotes(*this, Tag, Info); + ProcessVersionedAPINotes(*this, Tag, Info, SliceGroup); } return; @@ -1268,9 +1300,9 @@ void Sema::ProcessAPINotes(Decl *D) { // Typedefs if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext); - ProcessVersionedAPINotes(*this, Typedef, Info); + ProcessVersionedAPINotes(*this, Typedef, Info, SliceGroup); } return; @@ -1281,9 +1313,9 @@ void Sema::ProcessAPINotes(Decl *D) { if (DC->getRedeclContext()->isFileContext() || DC->getRedeclContext()->isExternCContext()) { if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { auto Info = Reader->lookupEnumConstant(EnumConstant->getName()); - ProcessVersionedAPINotes(*this, EnumConstant, Info); + ProcessVersionedAPINotes(*this, EnumConstant, Info, SliceGroup); } return; @@ -1334,7 +1366,7 @@ void Sema::ProcessAPINotes(Decl *D) { // Objective-C methods. if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { if (auto Context = GetContext(Reader)) { // Map the selector. Selector Sel = Method->getSelector(); @@ -1352,21 +1384,21 @@ void Sema::ProcessAPINotes(Decl *D) { auto Info = Reader->lookupObjCMethod(*Context, SelectorRef, Method->isInstanceMethod()); - ProcessVersionedAPINotes(*this, Method, Info); + ProcessVersionedAPINotes(*this, Method, Info, SliceGroup); } } } // Objective-C properties. if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { - for (auto Reader : APINotes.findAPINotes(D->getLocation())) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { if (auto Context = GetContext(Reader)) { bool isInstanceProperty = (Property->getPropertyAttributesAsWritten() & ObjCPropertyAttribute::kind_class) == 0; auto Info = Reader->lookupObjCProperty(*Context, Property->getName(), isInstanceProperty); - ProcessVersionedAPINotes(*this, Property, Info); + ProcessVersionedAPINotes(*this, Property, Info, SliceGroup); } } @@ -1381,7 +1413,7 @@ void Sema::ProcessAPINotes(Decl *D) { !isa<CXXConversionDecl>(CXXMethod)) { auto ParameterSelectorCandidates = getAPINotesParameterSelectorCandidates(*this, CXXMethod); - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { if (auto Context = UnwindTagContext(TagContext, APINotes)) { std::string MethodName; if (CXXMethod->isOverloadedOperator()) @@ -1392,7 +1424,7 @@ void Sema::ProcessAPINotes(Decl *D) { MethodName = CXXMethod->getName(); auto Info = Reader->lookupCXXMethod(Context->id, MethodName); - ProcessVersionedAPINotes(*this, CXXMethod, Info); + ProcessVersionedAPINotes(*this, CXXMethod, Info, SliceGroup); if (ParameterSelectorCandidates) processExactAPINotes<api_notes::CXXMethodInfo>( @@ -1400,7 +1432,11 @@ void Sema::ProcessAPINotes(Decl *D) { [&](ArrayRef<std::string> Parameters) { return Reader->lookupCXXMethod(Context->id, MethodName, Parameters); - }); + }, + // A second competition against the same reader; see finding 2 + // in the review and the SwiftVersionedSlice comment in + // Attr.td. + Readers.size() + SliceGroup); if (ParameterSelectorCandidates) { auto &DiagnosticState = @@ -1423,20 +1459,20 @@ void Sema::ProcessAPINotes(Decl *D) { if (auto Field = dyn_cast<FieldDecl>(D)) { if (!Field->isUnnamedBitField() && !Field->isAnonymousStructOrUnion()) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { if (auto Context = UnwindTagContext(TagContext, APINotes)) { auto Info = Reader->lookupField(Context->id, Field->getName()); - ProcessVersionedAPINotes(*this, Field, Info); + ProcessVersionedAPINotes(*this, Field, Info, SliceGroup); } } } } if (auto Tag = dyn_cast<TagDecl>(D)) { - for (auto Reader : Readers) { + for (auto [SliceGroup, Reader] : llvm::enumerate(Readers)) { if (auto Context = UnwindTagContext(TagContext, APINotes)) { auto Info = Reader->lookupTag(Tag->getName(), Context); - ProcessVersionedAPINotes(*this, Tag, Info); + ProcessVersionedAPINotes(*this, Tag, Info, SliceGroup); } } } diff --git a/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes b/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes index 572c714b3d61a..bbc2498a75192 100644 --- a/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes +++ b/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.apinotes @@ -18,6 +18,8 @@ Classes: Functions: - Name: unversionedRenameDUMP SwiftName: 'unversionedRename_NOTES()' + - Name: keylessSliceDUMP + SwiftName: 'keylessSlice_NOTES()' Tags: - Name: APINotedFlagEnum FlagEnum: true @@ -75,6 +77,8 @@ SwiftVersions: - Name: Swift3RenamedAlsoDUMP SwiftName: SpecialSwift3Also Functions: + # Names the declaration and sets no key, on purpose. + - Name: keylessSliceDUMP - Name: moveToPointDUMP SwiftName: 'moveTo(a:b:)' - Name: acceptClosure diff --git a/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h b/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h index 9ce95633c523b..8fbca41ee4335 100644 --- a/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h +++ b/clang/test/APINotes/Inputs/Frameworks/VersionedKit.framework/Headers/VersionedKit.h @@ -2,6 +2,8 @@ void moveToPointDUMP(double x, double y) __attribute__((swift_name("moveTo(x:y:) void unversionedRenameDUMP(void) __attribute__((swift_name("unversionedRename_HEADER()"))); +void keylessSliceDUMP(void); + void acceptClosure(void (^ __attribute__((noescape)) block)(void)); void privateFunc(void) __attribute__((swift_private)); diff --git a/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes b/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes index 14c77afd8c30a..ce75e7cfb6a63 100644 --- a/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes +++ b/clang/test/APINotes/Inputs/Headers/ExportAs.apinotes @@ -3,3 +3,10 @@ Globals: - Name: globalInt Availability: none AvailabilityMsg: "oh no" + - Name: sliceGroupProbe + SwiftPrivate: true +SwiftVersions: + - Version: 4.0 + Globals: + - Name: sliceGroupProbe + SwiftPrivate: false diff --git a/clang/test/APINotes/Inputs/Headers/ExportAsCore.apinotes b/clang/test/APINotes/Inputs/Headers/ExportAsCore.apinotes new file mode 100644 index 0000000000000..54a74119a8eea --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/ExportAsCore.apinotes @@ -0,0 +1,9 @@ +Name: ExportAsCore +Globals: + - Name: sliceGroupProbe + SwiftName: 'fromCoreUnversioned' +SwiftVersions: + - Version: 3.0 + Globals: + - Name: sliceGroupProbe + SwiftName: 'fromCoreV3' diff --git a/clang/test/APINotes/Inputs/Headers/ExportAsCore.h b/clang/test/APINotes/Inputs/Headers/ExportAsCore.h index f7674c19935d6..2898ef1a60ced 100644 --- a/clang/test/APINotes/Inputs/Headers/ExportAsCore.h +++ b/clang/test/APINotes/Inputs/Headers/ExportAsCore.h @@ -1 +1,6 @@ static int globalInt = 123; + +// Annotated by two readers at once: ExportAsCore.apinotes, and ExportAs.apinotes +// because ExportAsCore is export_as ExportAs. Each reader is its own slice +// group. See slice-groups.c. +static int sliceGroupProbe = 0; diff --git a/clang/test/APINotes/Inputs/Headers/SliceGroupsExact.apinotes b/clang/test/APINotes/Inputs/Headers/SliceGroupsExact.apinotes new file mode 100644 index 0000000000000..e51693afbb10b --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/SliceGroupsExact.apinotes @@ -0,0 +1,19 @@ +Name: SliceGroupsExact +Functions: + - Name: sliceGroupExactProbe + SwiftName: 'broadUnversioned(_:)' + - Name: sliceGroupExactProbe + Where: + Parameters: + - int + SwiftName: 'exactUnversioned(_:)' +SwiftVersions: + - Version: 3.0 + Functions: + - Name: sliceGroupExactProbe + SwiftName: 'broadV3(_:)' + - Name: sliceGroupExactProbe + Where: + Parameters: + - int + SwiftName: 'exactV3(_:)' diff --git a/clang/test/APINotes/Inputs/Headers/SliceGroupsExact.h b/clang/test/APINotes/Inputs/Headers/SliceGroupsExact.h new file mode 100644 index 0000000000000..b65c5e33b34d2 --- /dev/null +++ b/clang/test/APINotes/Inputs/Headers/SliceGroupsExact.h @@ -0,0 +1,3 @@ +// One declaration reached by two lookups against the same reader: the broad +// entry, and the exact Where: Parameters entry. See slice-groups-exact.c. +void sliceGroupExactProbe(int x); diff --git a/clang/test/APINotes/Inputs/Headers/module.modulemap b/clang/test/APINotes/Inputs/Headers/module.modulemap index a9b273ccc90e6..0a0cbf0115dee 100644 --- a/clang/test/APINotes/Inputs/Headers/module.modulemap +++ b/clang/test/APINotes/Inputs/Headers/module.modulemap @@ -84,3 +84,7 @@ module RedeclAnnotation { header "RedeclAnnotation.h" export * } + +module SliceGroupsExact { + header "SliceGroupsExact.h" +} diff --git a/clang/test/APINotes/properties.m b/clang/test/APINotes/properties.m index 79b5e2b10c47c..3cddab8099396 100644 --- a/clang/test/APINotes/properties.m +++ b/clang/test/APINotes/properties.m @@ -15,28 +15,28 @@ // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyInVersion3 'id' // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> -// CHECK-4-NEXT: SwiftVersionedAdditionAttr {{.+}} 3.0{{$}} +// CHECK-4-NEXT: SwiftVersionedAdditionAttr {{.+}} 3.0 0{{$}} // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> // CHECK-NOT: Attr // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClassInVersion3 'id' // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> -// CHECK-4-NEXT: SwiftVersionedAdditionAttr {{.+}} 3.0{{$}} +// CHECK-4-NEXT: SwiftVersionedAdditionAttr {{.+}} 3.0 0{{$}} // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> // CHECK-NOT: Attr // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyExceptInVersion3 'id' -// CHECK-3-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} +// CHECK-3-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive 0{{$}} // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> -// CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} +// CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} 0{{$}} // CHECK-NOT: Attr // CHECK-LABEL: ObjCPropertyDecl {{.+}} accessorsOnlyForClassExceptInVersion3 'id' -// CHECK-3-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} +// CHECK-3-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive 0{{$}} // CHECK-3-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> // CHECK-4-NEXT: SwiftImportPropertyAsAccessorsAttr {{.+}} <<invalid sloc>> -// CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} +// CHECK-4-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} 0{{$}} // CHECK-NOT: Attr // CHECK-LABEL: Decl diff --git a/clang/test/APINotes/slice-groups-exact.c b/clang/test/APINotes/slice-groups-exact.c new file mode 100644 index 0000000000000..d740723872e54 --- /dev/null +++ b/clang/test/APINotes/slice-groups-exact.c @@ -0,0 +1,39 @@ +// Two lookups against a single API notes reader, which is the case that makes +// the slice group distinct from a reader index. +// +// Sema runs a broad lookup for a global function and, when the sidecar carries +// a `Where: Parameters:` entry, a second exact lookup beside it. Each call runs +// its own version selection and each winner is applied, so the two are separate +// competitions even though they read the same file. If both stamped the same +// group, a consumer that recomputes the selection would pool all four slices +// into one competition, pick a single winner, and silently drop either the +// broad annotation or the exact one. +// +// slice-groups.c covers the other way a second group arises, two readers via +// export_as. This one cannot be expressed with one lookup per reader, so it is +// the test that pins the group to the lookup rather than to the reader. + +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clang_cc1 -fswift-version-independent-apinotes -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter sliceGroupExactProbe -x c | FileCheck %s + +#include "SliceGroupsExact.h" + +// CHECK: Dumping sliceGroupExactProbe: +// CHECK: FunctionDecl {{.+}} imported in SliceGroupsExact sliceGroupExactProbe + +// The broad lookup's two slices share one group. +// CHECK: SwiftVersionedSliceAttr {{.+}} Implicit 0 0{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 0{{$}} +// CHECK-NEXT: SwiftNameAttr {{.+}} "broadUnversioned(_:)" +// CHECK-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-NEXT: SwiftNameAttr {{.+}} "broadV3(_:)" + +// The exact lookup's two slices share a different group. The trailing 1 is the +// assertion: it must not be 0, or the two competitions have been pooled. +// CHECK-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 0 1{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 1{{$}} +// CHECK-NEXT: SwiftNameAttr {{.+}} "exactUnversioned(_:)" +// CHECK-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 1{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 1{{$}} +// CHECK-NEXT: SwiftNameAttr {{.+}} "exactV3(_:)" diff --git a/clang/test/APINotes/slice-groups.c b/clang/test/APINotes/slice-groups.c new file mode 100644 index 0000000000000..f9f575393f3af --- /dev/null +++ b/clang/test/APINotes/slice-groups.c @@ -0,0 +1,39 @@ +// A declaration annotated by two API notes readers at once, which is what makes +// the slice group observable. ExportAsCore is `export_as ExportAs`, so +// tryAPINotes loads ExportAsCore.apinotes and then ExportAs.apinotes from the +// same directory. Both are public readers. +// +// Clang runs version selection once per lookup and applies every winner, so the +// two readers are two competitions. The group ordinal is what tells a consumer +// which slices are rivals; pooling them would let one reader's slice suppress +// the other's. Every other test in this directory has a single reader, so this +// is the only one where a wrong or swapped group is visible at all. +// +// This is the sibling of versioned-version-independent.m, which covers the +// keyless-slice case on a single reader. + +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clang_cc1 -fswift-version-independent-apinotes -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fdisable-module-hash -fapinotes-modules -I %S/Inputs/Headers %s -ast-dump -ast-dump-filter sliceGroupProbe -x c | FileCheck %s + +#include "ExportAs.h" + +// CHECK: Dumping sliceGroupProbe: +// CHECK: VarDecl {{.+}} imported in ExportAsCore sliceGroupProbe 'int' + +// Group 0 is ExportAsCore.apinotes: an unversioned slice and a 3.0 slice. +// CHECK: SwiftVersionedSliceAttr {{.+}} Implicit 0 0{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 0{{$}} +// CHECK-NEXT: SwiftNameAttr {{.+}} "fromCoreUnversioned" +// CHECK-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-NEXT: SwiftNameAttr {{.+}} "fromCoreV3" + +// Group 1 is ExportAs.apinotes, reached through export_as. The trailing 1 is +// the whole point of this test: nothing else in the suite produces a nonzero +// group, so a bug that collapsed the two readers onto one group, or swapped +// them, would pass everywhere else. +// CHECK-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 0 1{{$}} +// CHECK-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 1{{$}} +// CHECK-NEXT: SwiftPrivateAttr +// CHECK-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 4.0 1{{$}} +// CHECK-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 4.0 {{[0-9]+}} 1{{$}} diff --git a/clang/test/APINotes/versioned-version-independent.m b/clang/test/APINotes/versioned-version-independent.m index da8b34a1d9ba3..a832fed6f3758 100644 --- a/clang/test/APINotes/versioned-version-independent.m +++ b/clang/test/APINotes/versioned-version-independent.m @@ -7,30 +7,54 @@ #import <VersionedKit/VersionedKit.h> +// Each slice an API notes lookup supplied is recorded by a +// SwiftVersionedSliceAttr, whether or not it went on to set a key, and both it +// and the wrappers carry the slice group they belong to. The trailing 0 on +// every line below is that group: one lookup here, because VersionedKit has a +// single reader. + // CHECK-VERSIONED-DUMP-LABEL: Dumping moveToPointDUMP // CHECK-VERSIONED-DUMP: SwiftNameAttr {{.+}} "moveTo(x:y:)" -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "moveTo(a:b:)" // CHECK-VERSIONED-DUMP-LABEL: Dumping unversionedRenameDUMP // CHECK-VERSIONED-DUMP: SwiftNameAttr {{.+}} "unversionedRename_HEADER()" -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "unversionedRename_NOTES()" +// The case this attribute exists for: the 3.0 slice names the declaration and +// sets no key. Selecting it suppresses the unversioned rename, and no addition +// wrapper records that, so the bare slice marker is the only evidence the slice +// exists. The -NEXT chain is what makes this a real assertion: it pins the 3.0 +// marker directly after the unversioned rename, so no addition wrapper for 3.0 +// can sit between them. +// CHECK-VERSIONED-DUMP-LABEL: Dumping keylessSliceDUMP +// CHECK-VERSIONED-DUMP: SwiftVersionedSliceAttr {{.+}} Implicit 0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "keylessSlice_NOTES()" +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} + // CHECK-VERSIONED-DUMP-LABEL: Dumping TestGenericDUMP -// CHECK-VERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 +// CHECK-VERSIONED-DUMP: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftImportAsNonGenericAttr {{.+}} <<invalid sloc>> // CHECK-VERSIONED-DUMP: Swift3RenamedOnlyDUMP -// CHECK-VERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 +// CHECK-VERSIONED-DUMP: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift3Name" // CHECK-VERSIONED-DUMP: Swift3RenamedAlsoDUMP // CHECK-VERSIONED-DUMP: SwiftNameAttr {{.+}} "Swift4Name" -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedSliceAttr {{.+}} Implicit 3.0 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift3Also" // CHECK-VERSIONED-DUMP: Swift4RenamedDUMP -// CHECK-VERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 4 +// CHECK-VERSIONED-DUMP: SwiftVersionedSliceAttr {{.+}} Implicit 4 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 4 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift4Name" diff --git a/clang/test/APINotes/versioned.m b/clang/test/APINotes/versioned.m index 264edde2a04fc..3f56b1204625d 100644 --- a/clang/test/APINotes/versioned.m +++ b/clang/test/APINotes/versioned.m @@ -16,50 +16,64 @@ // CHECK-VERSIONED:__attribute__((swift_name("moveTo(a:b:)"))) void moveToPointDUMP(double x, double y); // CHECK-DUMP-LABEL: Dumping moveToPointDUMP -// CHECK-VERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} +// CHECK-VERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "moveTo(x:y:)" // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "moveTo(a:b:)" // CHECK-UNVERSIONED-DUMP: SwiftNameAttr {{.+}} "moveTo(x:y:)" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0{{$}} +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "moveTo(a:b:)" // CHECK-DUMP-NOT: Attr // CHECK-DUMP-LABEL: Dumping unversionedRenameDUMP // CHECK-DUMP: in VersionedKit unversionedRenameDUMP -// CHECK-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 IsReplacedByActive{{$}} +// CHECK-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 0 IsReplacedByActive 0{{$}} // CHECK-DUMP-NEXT: SwiftNameAttr {{.+}} "unversionedRename_HEADER()" // CHECK-DUMP-NEXT: SwiftNameAttr {{.+}} "unversionedRename_NOTES()" // CHECK-DUMP-NOT: Attr +// A 3.0 slice that names this declaration and sets no key. This is the legacy +// behavior that -fswift-version-independent-apinotes has to let a client +// reproduce, so it is worth pinning here as the reference. +// CHECK-DUMP-LABEL: Dumping keylessSliceDUMP +// CHECK-DUMP: in VersionedKit keylessSliceDUMP +// At the default version the keyless slice does not qualify, so the unversioned +// rename applies live. +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "keylessSlice_NOTES()" +// At 3.0 the keyless slice wins and suppresses the unversioned rename. What +// survives is a superseded wrapper, and there is no live SwiftNameAttr. +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive 0{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "keylessSlice_NOTES()" +// CHECK-DUMP-NOT: Attr + // CHECK-DUMP-LABEL: Dumping TestGenericDUMP // CHECK-VERSIONED-DUMP: SwiftImportAsNonGenericAttr {{.+}} <<invalid sloc>> -// CHECK-UNVERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0{{$}} +// CHECK-UNVERSIONED-DUMP: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftImportAsNonGenericAttr {{.+}} <<invalid sloc>> // CHECK-DUMP-NOT: Attr // CHECK-DUMP-LABEL: Dumping Swift3RenamedOnlyDUMP // CHECK-DUMP: in VersionedKit Swift3RenamedOnlyDUMP -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} IsReplacedByActive{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedRemovalAttr {{.+}} Implicit 3.0 {{[0-9]+}} IsReplacedByActive 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift3Name" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0{{$}} +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "SpecialSwift3Name" // CHECK-DUMP-NOT: Attr // CHECK-DUMP-LABEL: Dumping Swift3RenamedAlsoDUMP // CHECK-DUMP: in VersionedKit Swift3RenamedAlsoDUMP -// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive{{$}} +// CHECK-VERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 IsReplacedByActive 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <line:{{.+}}, col:{{.+}}> "Swift4Name" // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift3Also" // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <line:{{.+}}, col:{{.+}}> "Swift4Name" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0{{$}} +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 3.0 0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "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: SwiftVersionedRemovalAttr {{.+}} Implicit 4 {{[0-9]+}} IsReplacedByActive 0{{$}} // CHECK-VERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} "SpecialSwift4Name" -// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 4{{$}} +// CHECK-UNVERSIONED-DUMP-NEXT: SwiftVersionedAdditionAttr {{.+}} Implicit 4 0{{$}} // CHECK-UNVERSIONED-DUMP-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "SpecialSwift4Name" // CHECK-DUMP-NOT: Attr _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
