Skip to content

Commit 85278f8

Browse files
committed
[ASTGen] Generate '@_rawLayout' attribute
Introduce 'generateTypeRepr(expr:)'.
1 parent 14dd14d commit 85278f8

File tree

5 files changed

+296
-1
lines changed

5 files changed

+296
-1
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 17 additions & 0 deletions
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

Lines changed: 27 additions & 0 deletions
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

Lines changed: 136 additions & 1 deletion
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,141 @@ 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+
return self.generateTypeRepr(expr: node)
1471+
}
1472+
1473+
func generateRawLayoutAttr(attribute node: AttributeSyntax) -> BridgedRawLayoutAttr? {
1474+
self.generateWithLabeledExprListArguments(attribute: node) { args in
1475+
switch args.first?.label?.rawText {
1476+
case "size":
1477+
return generateSizeAlignment()
1478+
case "like":
1479+
return generateScalarLike()
1480+
case "likeArrayOf":
1481+
return generateArrayLike()
1482+
default:
1483+
// TODO: Diagnose.
1484+
fatalError("invalid argument for @rawLayout attribute")
1485+
}
1486+
1487+
func generateSizeAlignment() -> BridgedRawLayoutAttr? {
1488+
guard let size = generateConsumingIntegerLiteralOption(label: "size") else {
1489+
// Should already be diagnosed.
1490+
return nil
1491+
}
1492+
guard let alignment = generateConsumingIntegerLiteralOption(label: "alignment") else {
1493+
// Should already be diagnosed.
1494+
return nil
1495+
}
1496+
return .createParsed(
1497+
self.ctx,
1498+
atLoc: self.generateSourceLoc(node.atSign),
1499+
range: self.generateAttrSourceRange(node),
1500+
size: size,
1501+
alignment: alignment
1502+
)
1503+
}
1504+
1505+
func generateScalarLike() -> BridgedRawLayoutAttr? {
1506+
let tyR = self.generateConsumingAttrOption(args: &args, label: "like") {
1507+
self.generateTypeRepr(expr: $0)
1508+
}
1509+
guard let tyR else {
1510+
return nil
1511+
}
1512+
1513+
guard let moveAsLike = args.isEmpty ? false : generateConsumingMoveAsLike() else {
1514+
return nil
1515+
}
1516+
1517+
return .createParsed(
1518+
self.ctx,
1519+
atLoc: self.generateSourceLoc(node.atSign),
1520+
range: self.generateAttrSourceRange(node),
1521+
like: tyR,
1522+
moveAsLike: moveAsLike
1523+
)
1524+
}
1525+
1526+
func generateArrayLike() -> BridgedRawLayoutAttr? {
1527+
let tyR = self.generateConsumingAttrOption(args: &args, label: "likeArrayOf") {
1528+
self.generateTypeRepr(expr: $0)
1529+
}
1530+
guard let tyR else {
1531+
return nil
1532+
}
1533+
1534+
// 'count:' can be integer literal or a generic parameter.
1535+
let count = self.generateConsumingAttrOption(args: &args, label: "count") {
1536+
self.generateValueOrType(expr: $0)
1537+
}
1538+
guard let count else {
1539+
return nil
1540+
}
1541+
1542+
guard let moveAsLike = args.isEmpty ? false : generateConsumingMoveAsLike() else {
1543+
return nil
1544+
}
1545+
1546+
return .createParsed(
1547+
self.ctx,
1548+
atLoc: self.generateSourceLoc(node.atSign),
1549+
range: self.generateAttrSourceRange(node),
1550+
likeArrayOf: tyR,
1551+
count: count,
1552+
moveAsLike: moveAsLike
1553+
)
1554+
}
1555+
1556+
func generateConsumingIntegerLiteralOption(label: SyntaxText) -> Int? {
1557+
self.generateConsumingAttrOption(args: &args, label: label) {
1558+
guard let integerExpr = $0.as(IntegerLiteralExprSyntax.self) else {
1559+
// TODO: Diagnose
1560+
fatalError("expected integer literal for '\(String(syntaxText: label)):' in @_rawLayout")
1561+
}
1562+
guard let count = integerExpr.representedLiteralValue else {
1563+
fatalError("invalid value literal for '\(String(syntaxText: label)):' in @_rawLayout")
1564+
}
1565+
return count
1566+
}
1567+
}
1568+
1569+
func generateConsumingMoveAsLike() -> Bool? {
1570+
self.generateConsumingPlainIdentifierAttrOption(args: &args) {
1571+
switch $0.rawText {
1572+
case "moveAsLike":
1573+
return true
1574+
default:
1575+
// TODO: Diagnose.
1576+
fatalError("expected 'moveAsLike' in @rawLayout attribute")
1577+
}
1578+
}
1579+
}
1580+
}
1581+
}
1582+
14481583
// FIXME: This is a decl modifier
14491584
func generateReferenceOwnershipAttr(attribute node: AttributeSyntax, attrName: SyntaxText)
14501585
-> BridgedReferenceOwnershipAttr?

lib/ASTGen/Sources/ASTGen/Types.swift

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,104 @@ extension ASTGenVisitor {
380380
}.bridgedArray(in: self)
381381
}
382382
}
383+
384+
extension ASTGenVisitor {
385+
struct GeneratedGenericArguments {
386+
var arguments: BridgedArrayRef = .init()
387+
var range: BridgedSourceRange = .init()
388+
}
389+
390+
/// Generate 'TypeRepr' from a expression, because 'conformances' arguments in
391+
/// macro role attributes are parsed as normal expressions.
392+
func generateTypeRepr(
393+
expr: ExprSyntax,
394+
genericArgs: GeneratedGenericArguments = GeneratedGenericArguments()
395+
) -> BridgedTypeRepr? {
396+
switch expr.as(ExprSyntaxEnum.self) {
397+
398+
case .typeExpr(let node):
399+
guard genericArgs.arguments.isEmpty else {
400+
break
401+
}
402+
return self.generate(type: node.type)
403+
404+
case .declReferenceExpr(let node):
405+
guard node.argumentNames == nil else {
406+
// 'Foo.bar(_:baz:)'
407+
break
408+
}
409+
let name = self.generateIdentifierAndSourceLoc(node.baseName)
410+
return BridgedUnqualifiedIdentTypeRepr .createParsed(
411+
self.ctx,
412+
name: name.identifier,
413+
nameLoc: name.sourceLoc,
414+
genericArgs: genericArgs.arguments,
415+
leftAngleLoc: genericArgs.range.start,
416+
rightAngleLoc: genericArgs.range.end
417+
).asTypeRepr
418+
419+
case .memberAccessExpr(let node):
420+
guard let parsedBase = node.base else {
421+
// Implicit member expressions. E.g. '.Foo'
422+
break
423+
}
424+
guard let base = self.generateTypeRepr(expr: parsedBase) else {
425+
// Unsupported base expr. E.g. 'foo().bar'
426+
return nil
427+
}
428+
guard node.declName.argumentNames == nil else {
429+
// Function name. E.g. 'Foo.bar(_:baz:)'
430+
break
431+
}
432+
let name = self.generateIdentifierAndSourceLoc(node.declName.baseName)
433+
return BridgedDeclRefTypeRepr.createParsed(
434+
self.ctx,
435+
base: base,
436+
name: name.identifier,
437+
nameLoc: name.sourceLoc,
438+
genericArguments: genericArgs.arguments,
439+
angleRange: genericArgs.range
440+
).asTypeRepr
441+
442+
case .genericSpecializationExpr(let node):
443+
guard genericArgs.arguments.isEmpty else {
444+
// TODO: Diagnose.
445+
break
446+
}
447+
guard node.expression.is(MemberAccessExprSyntax.self) || node.expression.is(DeclReferenceExprSyntax.self) else {
448+
break
449+
}
450+
let args = node.genericArgumentClause.arguments.lazy.map {
451+
self.generate(genericArgument: $0.argument)
452+
}
453+
return self.generateTypeRepr(
454+
expr: node.expression,
455+
genericArgs: GeneratedGenericArguments(
456+
arguments: args.bridgedArray(in: self),
457+
range: self.generateSourceRange(node.genericArgumentClause)
458+
)
459+
)
460+
461+
case .sequenceExpr(let node):
462+
// TODO: Support composition type?
463+
_ = node
464+
break
465+
466+
case .tupleExpr(let node):
467+
// TODO: Support tuple type?
468+
_ = node
469+
break
470+
471+
case .arrowExpr(let node):
472+
// TODO: Support function type?
473+
_ = node
474+
break
475+
476+
default:
477+
break
478+
}
479+
480+
// TODO: Diagnose
481+
fatalError("invalid/unimplemented expression for type")
482+
}
483+
}

test/ASTGen/attrs.swift

Lines changed: 15 additions & 0 deletions
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)