Skip to content

Commit 7b1d4df

Browse files
committed
ModuleInterface: Fix decl attribute corruption in private swiftinterfaces
Erroneous declaration attributes were sometimes being printed in the private swiftinterfaces of modules because the changes from #42276 were effectively corrupting the attribute list for any decl with sythesized conformances (e.g. `Equatable`, `Hashable`). It is necessary to clone the attributes before adding them to the synthesized conformance extension decls. Resolves rdar://94009296
1 parent d20b9a8 commit 7b1d4df

File tree

4 files changed

+74
-29
lines changed

4 files changed

+74
-29
lines changed

include/swift/AST/Attr.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,8 @@ class SPIAccessControlAttr final : public DeclAttribute,
11561156
SourceRange range,
11571157
ArrayRef<Identifier> spiGroups);
11581158

1159+
SPIAccessControlAttr *clone(ASTContext &C, bool implicit) const;
1160+
11591161
/// Name of SPIs declared by the attribute.
11601162
///
11611163
/// Note: A single SPI name per attribute is currently supported but this
@@ -1712,12 +1714,15 @@ class ProjectedValuePropertyAttr : public DeclAttribute {
17121714
}
17131715
};
17141716

1715-
/// Describe a symbol was originally defined in another module. For example, given
1717+
/// Describes a symbol that was originally defined in another module. For
1718+
/// example, given the following declaration:
1719+
///
17161720
/// \code
17171721
/// @_originallyDefinedIn(module: "Original", OSX 10.15) var foo: Int
17181722
/// \endcode
17191723
///
1720-
/// Where variable Foo has originally defined in another module called Original prior to OSX 10.15
1724+
/// The variable \p foo was originally defined in another module called
1725+
/// \p Original prior to OSX 10.15
17211726
class OriginallyDefinedInAttr: public DeclAttribute {
17221727
public:
17231728
OriginallyDefinedInAttr(SourceLoc AtLoc, SourceRange Range,
@@ -1730,6 +1735,8 @@ class OriginallyDefinedInAttr: public DeclAttribute {
17301735
Platform(Platform),
17311736
MovedVersion(MovedVersion) {}
17321737

1738+
OriginallyDefinedInAttr *clone(ASTContext &C, bool implicit) const;
1739+
17331740
// The original module name.
17341741
const StringRef OriginalModuleName;
17351742

lib/AST/Attr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,13 @@ OriginallyDefinedInAttr::isActivePlatform(const ASTContext &ctx) const {
17201720
return None;
17211721
}
17221722

1723+
OriginallyDefinedInAttr *OriginallyDefinedInAttr::clone(ASTContext &C,
1724+
bool implicit) const {
1725+
return new (C) OriginallyDefinedInAttr(
1726+
implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(),
1727+
OriginalModuleName, Platform, MovedVersion, implicit);
1728+
}
1729+
17231730
bool AvailableAttr::isLanguageVersionSpecific() const {
17241731
if (PlatformAgnostic ==
17251732
PlatformAgnosticAvailabilityKind::SwiftVersionSpecific)
@@ -1940,6 +1947,15 @@ SPIAccessControlAttr::create(ASTContext &context,
19401947
return new (mem) SPIAccessControlAttr(atLoc, range, spiGroups);
19411948
}
19421949

1950+
SPIAccessControlAttr *SPIAccessControlAttr::clone(ASTContext &C,
1951+
bool implicit) const {
1952+
auto *attr = new (C) SPIAccessControlAttr(
1953+
implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(),
1954+
getSPIGroups());
1955+
attr->setImplicit(implicit);
1956+
return attr;
1957+
}
1958+
19431959
DifferentiableAttr::DifferentiableAttr(bool implicit, SourceLoc atLoc,
19441960
SourceRange baseRange,
19451961
enum DifferentiabilityKind diffKind,

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,11 @@ class InheritedProtocolCollector {
318318
static const StringLiteral DummyProtocolName;
319319

320320
using AvailableAttrList = TinyPtrVector<const AvailableAttr *>;
321-
using OtherAttrList = TinyPtrVector<const DeclAttribute*>;
321+
using OriginallyDefinedInAttrList =
322+
TinyPtrVector<const OriginallyDefinedInAttr *>;
322323
using ProtocolAndAvailability =
323-
std::tuple<ProtocolDecl *, AvailableAttrList, bool /*isUnchecked*/,
324-
OtherAttrList>;
324+
std::tuple<ProtocolDecl *, AvailableAttrList, bool /*isUnchecked*/,
325+
OriginallyDefinedInAttrList>;
325326

326327
/// Protocols that will be included by the ASTPrinter without any extra work.
327328
SmallVector<ProtocolDecl *, 8> IncludedProtocols;
@@ -357,10 +358,12 @@ class InheritedProtocolCollector {
357358
return cache.getValue();
358359
}
359360

360-
static OtherAttrList getOtherAttrList(const Decl *D) {
361-
OtherAttrList results;
361+
static OriginallyDefinedInAttrList
362+
getOriginallyDefinedInAttrList(const Decl *D) {
363+
OriginallyDefinedInAttrList results;
362364
while (D) {
363-
for (auto *result: D->getAttrs().getAttributes<OriginallyDefinedInAttr>()) {
365+
for (auto *result :
366+
D->getAttrs().getAttributes<OriginallyDefinedInAttr>()) {
364367
results.push_back(result);
365368
}
366369
D = D->getDeclContext()->getAsDecl();
@@ -396,11 +399,9 @@ class InheritedProtocolCollector {
396399
if (canPrintNormally)
397400
IncludedProtocols.push_back(protoDecl);
398401
else
399-
ExtraProtocols.push_back(
400-
ProtocolAndAvailability(protoDecl,
401-
getAvailabilityAttrs(D, availableAttrs),
402-
inherited.isUnchecked,
403-
getOtherAttrList(D)));
402+
ExtraProtocols.push_back(ProtocolAndAvailability(
403+
protoDecl, getAvailabilityAttrs(D, availableAttrs),
404+
inherited.isUnchecked, getOriginallyDefinedInAttrList(D)));
404405
}
405406
// FIXME: This ignores layout constraints, but currently we don't support
406407
// any of those besides 'AnyObject'.
@@ -417,11 +418,9 @@ class InheritedProtocolCollector {
417418
for (auto *conf : localConformances) {
418419
if (conf->getSourceKind() != ConformanceEntryKind::Synthesized)
419420
continue;
420-
ExtraProtocols.push_back(
421-
ProtocolAndAvailability(conf->getProtocol(),
422-
getAvailabilityAttrs(D, availableAttrs),
423-
isUncheckedConformance(conf),
424-
getOtherAttrList(D)));
421+
ExtraProtocols.push_back(ProtocolAndAvailability(
422+
conf->getProtocol(), getAvailabilityAttrs(D, availableAttrs),
423+
isUncheckedConformance(conf), getOriginallyDefinedInAttrList(D)));
425424
}
426425
}
427426
}
@@ -628,7 +627,7 @@ class InheritedProtocolCollector {
628627
auto proto = std::get<0>(protoAndAvailability);
629628
auto availability = std::get<1>(protoAndAvailability);
630629
auto isUnchecked = std::get<2>(protoAndAvailability);
631-
auto otherAttrs = std::get<3>(protoAndAvailability);
630+
auto originallyDefinedInAttrs = std::get<3>(protoAndAvailability);
632631

633632
// Create a synthesized ExtensionDecl for the conformance.
634633
ASTContext &ctx = M->getASTContext();
@@ -640,21 +639,24 @@ class InheritedProtocolCollector {
640639
extension->setImplicit();
641640

642641
// Build up synthesized DeclAttributes for the extension.
643-
TinyPtrVector<const DeclAttribute *> attrs;
644-
attrs.insert(attrs.end(), availability.begin(), availability.end());
645-
auto spiAttributes =
646-
proto->getAttrs().getAttributes<SPIAccessControlAttr>();
647-
attrs.insert(attrs.end(), spiAttributes.begin(), spiAttributes.end());
648-
attrs.insert(attrs.end(), otherAttrs.begin(), otherAttrs.end());
642+
TinyPtrVector<const DeclAttribute *> clonedAttrs;
643+
for (auto *attr : availability) {
644+
clonedAttrs.push_back(attr->clone(ctx, /*implicit*/ true));
645+
}
646+
for (auto *attr : proto->getAttrs().getAttributes<SPIAccessControlAttr>()) {
647+
clonedAttrs.push_back(attr->clone(ctx, /*implicit*/ true));
648+
}
649+
for (auto *attr : originallyDefinedInAttrs) {
650+
clonedAttrs.push_back(attr->clone(ctx, /*implicit*/ true));
651+
}
649652

650653
// Since DeclAttributes is a linked list where each added attribute becomes
651654
// the head, we need to add these attributes in reverse order to reproduce
652655
// the order in which previous implementations printed these attributes.
653-
DeclAttributes declAttrs;
654-
for (auto attr = attrs.rbegin(), end = attrs.rend(); attr != end; ++attr) {
655-
declAttrs.add(const_cast<DeclAttribute *>(*attr));
656+
for (auto attr = clonedAttrs.rbegin(), end = clonedAttrs.rend();
657+
attr != end; ++attr) {
658+
extension->getAttrs().add(const_cast<DeclAttribute *>(*attr));
656659
}
657-
extension->getAttrs() = declAttrs;
658660

659661
ctx.evaluator.cacheOutput(ExtendedTypeRequest{extension},
660662
nominal->getDeclaredType());

test/ModuleInterface/synthesized.swift renamed to test/ModuleInterface/synthesized-conformances.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ public enum HasRawValue: Int {
1414
// CHECK-DAG: }
1515
} // CHECK: {{^}$}}
1616

17+
// CHECK-LABEL: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
18+
// CHECK-NEXT: public enum HasRawValueAndAvailability : Swift.Int {
19+
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
20+
public enum HasRawValueAndAvailability: Int {
21+
// CHECK-NEXT: case a, b, c
22+
case a, b, c
23+
// CHECK-DAG: public typealias RawValue = Swift.Int
24+
// CHECK-DAG: public init?(rawValue: Swift.Int)
25+
// CHECK-DAG: public var rawValue: Swift.Int {
26+
// CHECK-DAG: get{{$}}
27+
// CHECK-DAG: }
28+
} // CHECK: {{^}$}}
29+
1730
@objc public enum ObjCEnum: Int32 {
1831
case a, b = 5, c
1932
}
@@ -49,6 +62,13 @@ extension NoRawValueWithExplicitHashable : Hashable {
4962
// CHECK: extension synthesized.HasRawValue : Swift.Hashable {}
5063
// CHECK: extension synthesized.HasRawValue : Swift.RawRepresentable {}
5164

65+
// CHECK: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
66+
// CHECK-NEXT: extension synthesized.HasRawValueAndAvailability : Swift.Equatable {}
67+
// CHECK: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
68+
// CHECK-NEXT: extension synthesized.HasRawValueAndAvailability : Swift.Hashable {}
69+
// CHECK: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
70+
// CHECK-NEXT: extension synthesized.HasRawValueAndAvailability : Swift.RawRepresentable {}
71+
5272
// CHECK: extension synthesized.ObjCEnum : Swift.Equatable {}
5373
// CHECK: extension synthesized.ObjCEnum : Swift.Hashable {}
5474
// CHECK: extension synthesized.ObjCEnum : Swift.RawRepresentable {}

0 commit comments

Comments
 (0)