Skip to content

ModuleInterface: Fix decl attribute corruption in private swiftinterfaces #59128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,8 @@ class SPIAccessControlAttr final : public DeclAttribute,
SourceRange range,
ArrayRef<Identifier> spiGroups);

SPIAccessControlAttr *clone(ASTContext &C, bool implicit) const;

/// Name of SPIs declared by the attribute.
///
/// Note: A single SPI name per attribute is currently supported but this
Expand Down Expand Up @@ -1712,12 +1714,15 @@ class ProjectedValuePropertyAttr : public DeclAttribute {
}
};

/// Describe a symbol was originally defined in another module. For example, given
/// Describes a symbol that was originally defined in another module. For
/// example, given the following declaration:
///
/// \code
/// @_originallyDefinedIn(module: "Original", OSX 10.15) var foo: Int
/// \endcode
///
/// Where variable Foo has originally defined in another module called Original prior to OSX 10.15
/// The variable \p foo was originally defined in another module called
/// \p Original prior to OSX 10.15
class OriginallyDefinedInAttr: public DeclAttribute {
public:
OriginallyDefinedInAttr(SourceLoc AtLoc, SourceRange Range,
Expand All @@ -1730,6 +1735,8 @@ class OriginallyDefinedInAttr: public DeclAttribute {
Platform(Platform),
MovedVersion(MovedVersion) {}

OriginallyDefinedInAttr *clone(ASTContext &C, bool implicit) const;

// The original module name.
const StringRef OriginalModuleName;

Expand Down
16 changes: 16 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,13 @@ OriginallyDefinedInAttr::isActivePlatform(const ASTContext &ctx) const {
return None;
}

OriginallyDefinedInAttr *OriginallyDefinedInAttr::clone(ASTContext &C,
bool implicit) const {
return new (C) OriginallyDefinedInAttr(
implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(),
OriginalModuleName, Platform, MovedVersion, implicit);
}

bool AvailableAttr::isLanguageVersionSpecific() const {
if (PlatformAgnostic ==
PlatformAgnosticAvailabilityKind::SwiftVersionSpecific)
Expand Down Expand Up @@ -1940,6 +1947,15 @@ SPIAccessControlAttr::create(ASTContext &context,
return new (mem) SPIAccessControlAttr(atLoc, range, spiGroups);
}

SPIAccessControlAttr *SPIAccessControlAttr::clone(ASTContext &C,
bool implicit) const {
auto *attr = new (C) SPIAccessControlAttr(
implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(),
getSPIGroups());
attr->setImplicit(implicit);
return attr;
}

DifferentiableAttr::DifferentiableAttr(bool implicit, SourceLoc atLoc,
SourceRange baseRange,
enum DifferentiabilityKind diffKind,
Expand Down
56 changes: 29 additions & 27 deletions lib/Frontend/ModuleInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,11 @@ class InheritedProtocolCollector {
static const StringLiteral DummyProtocolName;

using AvailableAttrList = TinyPtrVector<const AvailableAttr *>;
using OtherAttrList = TinyPtrVector<const DeclAttribute*>;
using OriginallyDefinedInAttrList =
TinyPtrVector<const OriginallyDefinedInAttr *>;
using ProtocolAndAvailability =
std::tuple<ProtocolDecl *, AvailableAttrList, bool /*isUnchecked*/,
OtherAttrList>;
std::tuple<ProtocolDecl *, AvailableAttrList, bool /*isUnchecked*/,
OriginallyDefinedInAttrList>;

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

static OtherAttrList getOtherAttrList(const Decl *D) {
OtherAttrList results;
static OriginallyDefinedInAttrList
getOriginallyDefinedInAttrList(const Decl *D) {
OriginallyDefinedInAttrList results;
while (D) {
for (auto *result: D->getAttrs().getAttributes<OriginallyDefinedInAttr>()) {
for (auto *result :
D->getAttrs().getAttributes<OriginallyDefinedInAttr>()) {
results.push_back(result);
}
D = D->getDeclContext()->getAsDecl();
Expand Down Expand Up @@ -396,11 +399,9 @@ class InheritedProtocolCollector {
if (canPrintNormally)
IncludedProtocols.push_back(protoDecl);
else
ExtraProtocols.push_back(
ProtocolAndAvailability(protoDecl,
getAvailabilityAttrs(D, availableAttrs),
inherited.isUnchecked,
getOtherAttrList(D)));
ExtraProtocols.push_back(ProtocolAndAvailability(
protoDecl, getAvailabilityAttrs(D, availableAttrs),
inherited.isUnchecked, getOriginallyDefinedInAttrList(D)));
}
// FIXME: This ignores layout constraints, but currently we don't support
// any of those besides 'AnyObject'.
Expand All @@ -417,11 +418,9 @@ class InheritedProtocolCollector {
for (auto *conf : localConformances) {
if (conf->getSourceKind() != ConformanceEntryKind::Synthesized)
continue;
ExtraProtocols.push_back(
ProtocolAndAvailability(conf->getProtocol(),
getAvailabilityAttrs(D, availableAttrs),
isUncheckedConformance(conf),
getOtherAttrList(D)));
ExtraProtocols.push_back(ProtocolAndAvailability(
conf->getProtocol(), getAvailabilityAttrs(D, availableAttrs),
isUncheckedConformance(conf), getOriginallyDefinedInAttrList(D)));
}
}
}
Expand Down Expand Up @@ -628,7 +627,7 @@ class InheritedProtocolCollector {
auto proto = std::get<0>(protoAndAvailability);
auto availability = std::get<1>(protoAndAvailability);
auto isUnchecked = std::get<2>(protoAndAvailability);
auto otherAttrs = std::get<3>(protoAndAvailability);
auto originallyDefinedInAttrs = std::get<3>(protoAndAvailability);

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

// Build up synthesized DeclAttributes for the extension.
TinyPtrVector<const DeclAttribute *> attrs;
attrs.insert(attrs.end(), availability.begin(), availability.end());
auto spiAttributes =
proto->getAttrs().getAttributes<SPIAccessControlAttr>();
attrs.insert(attrs.end(), spiAttributes.begin(), spiAttributes.end());
attrs.insert(attrs.end(), otherAttrs.begin(), otherAttrs.end());
TinyPtrVector<const DeclAttribute *> clonedAttrs;
for (auto *attr : availability) {
clonedAttrs.push_back(attr->clone(ctx, /*implicit*/ true));
}
for (auto *attr : proto->getAttrs().getAttributes<SPIAccessControlAttr>()) {
clonedAttrs.push_back(attr->clone(ctx, /*implicit*/ true));
}
for (auto *attr : originallyDefinedInAttrs) {
clonedAttrs.push_back(attr->clone(ctx, /*implicit*/ true));
}

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

ctx.evaluator.cacheOutput(ExtendedTypeRequest{extension},
nominal->getDeclaredType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ public enum HasRawValue: Int {
// CHECK-DAG: }
} // CHECK: {{^}$}}

// CHECK-LABEL: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
// CHECK-NEXT: public enum HasRawValueAndAvailability : Swift.Int {
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
public enum HasRawValueAndAvailability: Int {
// CHECK-NEXT: case a, b, c
case a, b, c
// CHECK-DAG: public typealias RawValue = Swift.Int
// CHECK-DAG: public init?(rawValue: Swift.Int)
// CHECK-DAG: public var rawValue: Swift.Int {
// CHECK-DAG: get{{$}}
// CHECK-DAG: }
} // CHECK: {{^}$}}

@objc public enum ObjCEnum: Int32 {
case a, b = 5, c
}
Expand Down Expand Up @@ -49,6 +62,13 @@ extension NoRawValueWithExplicitHashable : Hashable {
// CHECK: extension synthesized.HasRawValue : Swift.Hashable {}
// CHECK: extension synthesized.HasRawValue : Swift.RawRepresentable {}

// CHECK: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
// CHECK-NEXT: extension synthesized.HasRawValueAndAvailability : Swift.Equatable {}
// CHECK: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
// CHECK-NEXT: extension synthesized.HasRawValueAndAvailability : Swift.Hashable {}
// CHECK: @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
// CHECK-NEXT: extension synthesized.HasRawValueAndAvailability : Swift.RawRepresentable {}

// CHECK: extension synthesized.ObjCEnum : Swift.Equatable {}
// CHECK: extension synthesized.ObjCEnum : Swift.Hashable {}
// CHECK: extension synthesized.ObjCEnum : Swift.RawRepresentable {}
Expand Down