Skip to content

Commit bdc953f

Browse files
authored
Merge pull request #79629 from rintaro/astgen-rawlayout
[ASTGen] Generate '@_rawLayout' attribute
2 parents 2760b0a + 924e1e8 commit bdc953f

File tree

5 files changed

+294
-1
lines changed

5 files changed

+294
-1
lines changed

include/swift/AST/ASTBridging.h

+17
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,23 @@ BridgedRawDocCommentAttr
11941194
BridgedRawDocCommentAttr_createParsed(BridgedASTContext cContext,
11951195
BridgedCharSourceRange cRange);
11961196

1197+
SWIFT_NAME("BridgedRawLayoutAttr.createParsed(_:atLoc:range:size:alignment:)")
1198+
BridgedRawLayoutAttr BridgedStorageRestrictionsAttr_createParsed(
1199+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
1200+
BridgedSourceRange cRange, size_t size, size_t alignment);
1201+
1202+
SWIFT_NAME("BridgedRawLayoutAttr.createParsed(_:atLoc:range:like:moveAsLike:)")
1203+
BridgedRawLayoutAttr BridgedStorageRestrictionsAttr_createParsed(
1204+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
1205+
BridgedSourceRange cRange, BridgedTypeRepr cLikeType, bool moveAsLike);
1206+
1207+
SWIFT_NAME("BridgedRawLayoutAttr.createParsed(_:atLoc:range:likeArrayOf:count:"
1208+
"moveAsLike:)")
1209+
BridgedRawLayoutAttr BridgedStorageRestrictionsAttr_createParsed(
1210+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
1211+
BridgedSourceRange cRange, BridgedTypeRepr cLikeType,
1212+
BridgedTypeRepr cCountType, bool moveAsLike);
1213+
11971214
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedReferenceOwnership {
11981215
BridgedReferenceOwnershipStrong,
11991216
BridgedReferenceOwnershipWeak,

lib/AST/Bridging/DeclAttributeBridging.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,33 @@ BridgedRawDocCommentAttr_createParsed(BridgedASTContext cContext,
632632
return new (cContext.unbridged()) RawDocCommentAttr(cRange.unbridged());
633633
}
634634

635+
BridgedRawLayoutAttr BridgedStorageRestrictionsAttr_createParsed(
636+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
637+
BridgedSourceRange cRange, size_t size, size_t alignment) {
638+
return new (cContext.unbridged())
639+
RawLayoutAttr(size, alignment, cAtLoc.unbridged(), cRange.unbridged());
640+
}
641+
642+
SWIFT_NAME("BridgedRawLayoutAttr.createParsed(_:atLoc:range:like:moveAsLike:)")
643+
BridgedRawLayoutAttr BridgedStorageRestrictionsAttr_createParsed(
644+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
645+
BridgedSourceRange cRange, BridgedTypeRepr cLikeType, bool moveAsLike) {
646+
return new (cContext.unbridged())
647+
RawLayoutAttr(cLikeType.unbridged(), moveAsLike, cAtLoc.unbridged(),
648+
cRange.unbridged());
649+
}
650+
651+
SWIFT_NAME("BridgedRawLayoutAttr.createParsed(_:atLoc:range:likeArrayOf:count:"
652+
"moveAsLike:)")
653+
BridgedRawLayoutAttr BridgedStorageRestrictionsAttr_createParsed(
654+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
655+
BridgedSourceRange cRange, BridgedTypeRepr cLikeType,
656+
BridgedTypeRepr cCountType, bool moveAsLike) {
657+
return new (cContext.unbridged())
658+
RawLayoutAttr(cLikeType.unbridged(), cCountType.unbridged(), moveAsLike,
659+
cAtLoc.unbridged(), cRange.unbridged());
660+
}
661+
635662
ReferenceOwnership unbridged(BridgedReferenceOwnership kind) {
636663
switch (kind) {
637664
case BridgedReferenceOwnershipStrong:

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

+137-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ extension ASTGenVisitor {
166166
case .projectedValueProperty:
167167
return handle(self.generateProjectedValuePropertyAttr(attribute: node)?.asDeclAttribute)
168168
case .rawLayout:
169-
fatalError("unimplemented")
169+
return handle(self.generateRawLayoutAttr(attribute: node)?.asDeclAttribute)
170170
case .section:
171171
return handle(self.generateSectionAttr(attribute: node)?.asDeclAttribute)
172172
case .semantics:
@@ -1445,6 +1445,142 @@ extension ASTGenVisitor {
14451445
)
14461446
}
14471447

1448+
func generateValueOrType(expr node: ExprSyntax) -> BridgedTypeRepr? {
1449+
var node = node
1450+
1451+
// Try value first.
1452+
let minusLoc: BridgedSourceLoc
1453+
if let prefixExpr = node.as(PrefixOperatorExprSyntax.self),
1454+
prefixExpr.operator.rawText == "-",
1455+
prefixExpr.expression.is(IntegerLiteralExprSyntax.self) {
1456+
minusLoc = self.generateSourceLoc(prefixExpr.operator)
1457+
node = prefixExpr.expression
1458+
} else {
1459+
minusLoc = nil
1460+
}
1461+
if let integerExpr = node.as(IntegerLiteralExprSyntax.self) {
1462+
let value = self.copyAndStripUnderscores(text: integerExpr.literal.rawText)
1463+
return BridgedIntegerTypeRepr.createParsed(
1464+
self.ctx,
1465+
string: value,
1466+
loc: self.generateSourceLoc(node), minusLoc: minusLoc
1467+
).asTypeRepr
1468+
}
1469+
1470+
assert(!minusLoc.isValid)
1471+
return self.generateTypeRepr(expr: node)
1472+
}
1473+
1474+
func generateRawLayoutAttr(attribute node: AttributeSyntax) -> BridgedRawLayoutAttr? {
1475+
self.generateWithLabeledExprListArguments(attribute: node) { args in
1476+
switch args.first?.label?.rawText {
1477+
case "size":
1478+
return generateSizeAlignment()
1479+
case "like":
1480+
return generateScalarLike()
1481+
case "likeArrayOf":
1482+
return generateArrayLike()
1483+
default:
1484+
// TODO: Diagnose.
1485+
fatalError("invalid argument for @rawLayout attribute")
1486+
}
1487+
1488+
func generateSizeAlignment() -> BridgedRawLayoutAttr? {
1489+
guard let size = generateConsumingIntegerLiteralOption(label: "size") else {
1490+
// Should already be diagnosed.
1491+
return nil
1492+
}
1493+
guard let alignment = generateConsumingIntegerLiteralOption(label: "alignment") else {
1494+
// Should already be diagnosed.
1495+
return nil
1496+
}
1497+
return .createParsed(
1498+
self.ctx,
1499+
atLoc: self.generateSourceLoc(node.atSign),
1500+
range: self.generateAttrSourceRange(node),
1501+
size: size,
1502+
alignment: alignment
1503+
)
1504+
}
1505+
1506+
func generateScalarLike() -> BridgedRawLayoutAttr? {
1507+
let tyR = self.generateConsumingAttrOption(args: &args, label: "like") {
1508+
self.generateTypeRepr(expr: $0)
1509+
}
1510+
guard let tyR else {
1511+
return nil
1512+
}
1513+
1514+
guard let moveAsLike = args.isEmpty ? false : generateConsumingMoveAsLike() else {
1515+
return nil
1516+
}
1517+
1518+
return .createParsed(
1519+
self.ctx,
1520+
atLoc: self.generateSourceLoc(node.atSign),
1521+
range: self.generateAttrSourceRange(node),
1522+
like: tyR,
1523+
moveAsLike: moveAsLike
1524+
)
1525+
}
1526+
1527+
func generateArrayLike() -> BridgedRawLayoutAttr? {
1528+
let tyR = self.generateConsumingAttrOption(args: &args, label: "likeArrayOf") {
1529+
self.generateTypeRepr(expr: $0)
1530+
}
1531+
guard let tyR else {
1532+
return nil
1533+
}
1534+
1535+
// 'count:' can be integer literal or a generic parameter.
1536+
let count = self.generateConsumingAttrOption(args: &args, label: "count") {
1537+
self.generateValueOrType(expr: $0)
1538+
}
1539+
guard let count else {
1540+
return nil
1541+
}
1542+
1543+
guard let moveAsLike = args.isEmpty ? false : generateConsumingMoveAsLike() else {
1544+
return nil
1545+
}
1546+
1547+
return .createParsed(
1548+
self.ctx,
1549+
atLoc: self.generateSourceLoc(node.atSign),
1550+
range: self.generateAttrSourceRange(node),
1551+
likeArrayOf: tyR,
1552+
count: count,
1553+
moveAsLike: moveAsLike
1554+
)
1555+
}
1556+
1557+
func generateConsumingIntegerLiteralOption(label: SyntaxText) -> Int? {
1558+
self.generateConsumingAttrOption(args: &args, label: label) {
1559+
guard let integerExpr = $0.as(IntegerLiteralExprSyntax.self) else {
1560+
// TODO: Diagnose
1561+
fatalError("expected integer literal for '\(String(syntaxText: label)):' in @_rawLayout")
1562+
}
1563+
guard let count = integerExpr.representedLiteralValue else {
1564+
fatalError("invalid value literal for '\(String(syntaxText: label)):' in @_rawLayout")
1565+
}
1566+
return count
1567+
}
1568+
}
1569+
1570+
func generateConsumingMoveAsLike() -> Bool? {
1571+
self.generateConsumingPlainIdentifierAttrOption(args: &args) {
1572+
switch $0.rawText {
1573+
case "moveAsLike":
1574+
return true
1575+
default:
1576+
// TODO: Diagnose.
1577+
fatalError("expected 'moveAsLike' in @rawLayout attribute")
1578+
}
1579+
}
1580+
}
1581+
}
1582+
}
1583+
14481584
// FIXME: This is a decl modifier
14491585
func generateReferenceOwnershipAttr(attribute node: AttributeSyntax, attrName: SyntaxText)
14501586
-> BridgedReferenceOwnershipAttr?

lib/ASTGen/Sources/ASTGen/Types.swift

+98
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,101 @@ extension ASTGenVisitor {
460460
}.bridgedArray(in: self)
461461
}
462462
}
463+
464+
extension ASTGenVisitor {
465+
struct GeneratedGenericArguments {
466+
var arguments: BridgedArrayRef = .init()
467+
var range: BridgedSourceRange = .init()
468+
}
469+
470+
/// Generate 'TypeRepr' from a expression, because 'conformances' arguments in
471+
/// macro role attributes are parsed as normal expressions.
472+
func generateTypeRepr(
473+
expr node: ExprSyntax,
474+
genericArgs: GeneratedGenericArguments = GeneratedGenericArguments()
475+
) -> BridgedTypeRepr? {
476+
if !genericArgs.arguments.isEmpty {
477+
guard node.is(MemberAccessExprSyntax.self) || node.is(DeclReferenceExprSyntax.self) else {
478+
// TODO: Diagnose.
479+
fatalError("generic arguments cannot be applied")
480+
}
481+
}
482+
483+
switch node.as(ExprSyntaxEnum.self) {
484+
485+
case .typeExpr(let node):
486+
return self.generate(type: node.type)
487+
488+
case .declReferenceExpr(let node):
489+
guard node.argumentNames == nil else {
490+
// 'Foo.bar(_:baz:)'
491+
break
492+
}
493+
let name = self.generateIdentifierAndSourceLoc(node.baseName)
494+
return BridgedUnqualifiedIdentTypeRepr .createParsed(
495+
self.ctx,
496+
name: name.identifier,
497+
nameLoc: name.sourceLoc,
498+
genericArgs: genericArgs.arguments,
499+
leftAngleLoc: genericArgs.range.start,
500+
rightAngleLoc: genericArgs.range.end
501+
).asTypeRepr
502+
503+
case .memberAccessExpr(let node):
504+
guard let parsedBase = node.base else {
505+
// Implicit member expressions. E.g. '.Foo'
506+
break
507+
}
508+
guard let base = self.generateTypeRepr(expr: parsedBase) else {
509+
// Unsupported base expr. E.g. 'foo().bar'
510+
return nil
511+
}
512+
guard node.declName.argumentNames == nil else {
513+
// Function name. E.g. 'Foo.bar(_:baz:)'
514+
break
515+
}
516+
let name = self.generateIdentifierAndSourceLoc(node.declName.baseName)
517+
return BridgedDeclRefTypeRepr.createParsed(
518+
self.ctx,
519+
base: base,
520+
name: name.identifier,
521+
nameLoc: name.sourceLoc,
522+
genericArguments: genericArgs.arguments,
523+
angleRange: genericArgs.range
524+
).asTypeRepr
525+
526+
case .genericSpecializationExpr(let node):
527+
let args = node.genericArgumentClause.arguments.lazy.map {
528+
self.generate(genericArgument: $0.argument)
529+
}
530+
return self.generateTypeRepr(
531+
expr: node.expression,
532+
genericArgs: GeneratedGenericArguments(
533+
arguments: args.bridgedArray(in: self),
534+
range: self.generateSourceRange(node.genericArgumentClause)
535+
)
536+
)
537+
538+
case .sequenceExpr(let node):
539+
// TODO: Support composition type?
540+
_ = node
541+
break
542+
543+
case .tupleExpr(let node):
544+
// TODO: Support tuple type?
545+
_ = node
546+
break
547+
548+
case .arrowExpr(let node):
549+
// TODO: Support function type?
550+
_ = node
551+
break
552+
553+
default:
554+
break
555+
}
556+
557+
// TODO: Diagnose
558+
fatalError("invalid/unimplemented expression for type")
559+
}
560+
}

test/ASTGen/attrs.swift

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// RUN: -enable-experimental-feature ExecutionAttribute \
66
// RUN: -enable-experimental-feature Extern \
77
// RUN: -enable-experimental-feature LifetimeDependence \
8+
// RUN: -enable-experimental-feature RawLayout \
89
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
910
// RUN: -enable-experimental-move-only \
1011
// RUN: -enable-experimental-feature ParserASTGen \
@@ -15,6 +16,7 @@
1516
// RUN: -enable-experimental-feature ExecutionAttribute \
1617
// RUN: -enable-experimental-feature Extern \
1718
// RUN: -enable-experimental-feature LifetimeDependence \
19+
// RUN: -enable-experimental-feature RawLayout \
1820
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
1921
// RUN: -enable-experimental-move-only \
2022
// RUN: | %sanitize-address > %t/cpp-parser.ast
@@ -28,6 +30,7 @@
2830
// RUN: -enable-experimental-feature ExecutionAttribute \
2931
// RUN: -enable-experimental-feature Extern \
3032
// RUN: -enable-experimental-feature LifetimeDependence \
33+
// RUN: -enable-experimental-feature RawLayout \
3134
// RUN: -enable-experimental-feature SymbolLinkageMarkers \
3235
// RUN: -enable-experimental-move-only
3336

@@ -38,6 +41,7 @@
3841
// REQUIRES: swift_feature_ExecutionAttribute
3942
// REQUIRES: swift_feature_Extern
4043
// REQUIRES: swift_feature_LifetimeDependence
44+
// REQUIRES: swift_feature_RawLayout
4145
// REQUIRES: swift_feature_SymbolLinkageMarkers
4246

4347
// rdar://116686158
@@ -234,3 +238,14 @@ struct ReferenceOwnershipModifierTest<X: AnyObject> {
234238
unowned(safe) var unownedSafeValue: X
235239
unowned(unsafe) var unmanagedValue: X
236240
}
241+
242+
@_rawLayout(like: T) struct RawStorage<T>: ~Copyable {}
243+
@_rawLayout(likeArrayOf: T, count: 4) struct RawSmallArray<T>: ~Copyable {}
244+
@_rawLayout(size: 4, alignment: 4) struct Lock: ~Copyable {}
245+
246+
struct LayoutOuter {
247+
struct Nested<T> {
248+
var value: T
249+
}
250+
}
251+
@_rawLayout(like: LayoutOuter.Nested<Int>) struct TypeExprTest: ~Copyable {}

0 commit comments

Comments
 (0)