[ASTGen] Generate miscellaneous builtin pound

`#error`, `#warning`, and `#assert`.
Also #_hasSymbol statement condition
This commit is contained in:
Rintaro Ishizaki
2025-03-12 13:59:07 -07:00
parent 1a08018985
commit ac80775201
14 changed files with 503 additions and 150 deletions

View File

@@ -388,7 +388,7 @@ struct BridgedDeclObj {
BRIDGED_INLINE bool Destructor_isIsolated() const;
};
enum ENUM_EXTENSIBILITY_ATTR(open) BridgedASTNodeKind : uint8_t {
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedASTNodeKind : uint8_t {
BridgedASTNodeKindExpr,
BridgedASTNodeKindStmt,
BridgedASTNodeKindDecl
@@ -2323,6 +2323,13 @@ BridgedPoundAvailableInfo BridgedPoundAvailableInfo_createParsed(
BridgedSourceLoc cLParenLoc, BridgedArrayRef cSpecs,
BridgedSourceLoc cRParenLoc, bool isUnavailability);
SWIFT_NAME("BridgedStmtConditionElement.createHasSymbol(_:poundLoc:lParenLoc:"
"symbol:rParenLoc:)")
BridgedStmtConditionElement BridgedStmtConditionElement_createHasSymbol(
BridgedASTContext cContext, BridgedSourceLoc cPoundLoc,
BridgedSourceLoc cLParenLoc, BridgedNullableExpr cSymbolExpr,
BridgedSourceLoc cRParenLoc);
struct BridgedCaseLabelItemInfo {
SWIFT_NAME("isDefault")
bool IsDefault;
@@ -2425,6 +2432,11 @@ BridgedIfStmt BridgedIfStmt_createParsed(
BridgedSourceLoc cIfLoc, BridgedArrayRef cConds, BridgedBraceStmt cThen,
BridgedSourceLoc cElseLoc, BridgedNullableStmt cElse);
SWIFT_NAME("BridgedPoundAssertStmt.createParsed(_:range:condition:message:)")
BridgedPoundAssertStmt BridgedPoundAssertStmt_createParsed(
BridgedASTContext cContext, BridgedSourceRange cRange,
BridgedExpr cConditionExpr, BridgedStringRef cMessage);
SWIFT_NAME("BridgedRepeatWhileStmt.createParsed(_:labelInfo:repeatLoc:cond:"
"whileLoc:body:)")
BridgedRepeatWhileStmt BridgedRepeatWhileStmt_createParsed(
@@ -3110,6 +3122,15 @@ struct BridgedFingerprint {
BRIDGED_INLINE swift::Fingerprint unbridged() const;
};
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedPoundKeyword : uint8_t {
#define POUND_KEYWORD(NAME) BridgedPoundKeyword_##NAME,
#include "swift/AST/TokenKinds.def"
BridgedPoundKeyword_None,
};
SWIFT_NAME("BridgedPoundKeyword.init(from:)")
BridgedPoundKeyword BridgedPoundKeyword_fromString(BridgedStringRef cStr);
//===----------------------------------------------------------------------===//
// MARK: #if handling
//===----------------------------------------------------------------------===//

View File

@@ -149,3 +149,14 @@ BridgedOwnedString BridgedGenericSignature::getDebugDescription() const {
unbridged().print(os);
return BridgedOwnedString(str);
}
//===----------------------------------------------------------------------===//
// MARK: BridgedPoundKeyword
//===----------------------------------------------------------------------===//
BridgedPoundKeyword BridgedPoundKeyword_fromString(BridgedStringRef cStr) {
return llvm::StringSwitch<BridgedPoundKeyword>(cStr.unbridged())
#define POUND_KEYWORD(NAME) .Case(#NAME, BridgedPoundKeyword_##NAME)
#include "swift/AST/TokenKinds.def"
.Default(BridgedPoundKeyword_None);
}

View File

@@ -69,6 +69,15 @@ BridgedPoundAvailableInfo BridgedPoundAvailableInfo_createParsed(
cRParenLoc.unbridged(), isUnavailability);
}
BridgedStmtConditionElement BridgedStmtConditionElement_createHasSymbol(
BridgedASTContext cContext, BridgedSourceLoc cPoundLoc,
BridgedSourceLoc cLParenLoc, BridgedNullableExpr cSymbolExpr,
BridgedSourceLoc cRParenLoc) {
return StmtConditionElement(PoundHasSymbolInfo::create(
cContext.unbridged(), cPoundLoc.unbridged(), cLParenLoc.unbridged(),
cSymbolExpr.unbridged(), cRParenLoc.unbridged()));
}
BridgedBraceStmt BridgedBraceStmt_createParsed(BridgedASTContext cContext,
BridgedSourceLoc cLBLoc,
BridgedArrayRef elements,
@@ -229,6 +238,13 @@ BridgedIfStmt BridgedIfStmt_createParsed(
cThen.unbridged(), cElseLoc.unbridged(), cElse.unbridged());
}
BridgedPoundAssertStmt BridgedPoundAssertStmt_createParsed(
BridgedASTContext cContext, BridgedSourceRange cRange,
BridgedExpr cConditionExpr, BridgedStringRef cMessage) {
return new (cContext.unbridged()) PoundAssertStmt(
cRange.unbridged(), cConditionExpr.unbridged(), cMessage.unbridged());
}
BridgedRepeatWhileStmt BridgedRepeatWhileStmt_createParsed(
BridgedASTContext cContext, BridgedLabeledStmtInfo cLabelInfo,
BridgedSourceLoc cRepeatLoc, BridgedExpr cCond, BridgedSourceLoc cWhileLoc,

View File

@@ -58,38 +58,41 @@ struct ASTGenVisitor {
}
func generate(sourceFile node: SourceFileSyntax) -> [BridgedASTNode] {
var out = [BridgedASTNode]()
let isTopLevel = self.declContext.isModuleScopeContext
visitIfConfigElements(
node.statements,
of: CodeBlockItemSyntax.self,
split: Self.splitCodeBlockItemIfConfig
) { element in
func generateStmtOrExpr(_ body: () -> BridgedASTNode) -> BridgedASTNode {
if !isTopLevel {
return body()
// If not top-level, no need for 'TopLevelCodeDecl' treatment.
if !self.declContext.isModuleScopeContext {
return self.generate(codeBlockItemList: node.statements)
} else {
return self.generateTopLevel(codeBlockItemList: node.statements)
}
}
let topLevelDecl = BridgedTopLevelCodeDecl.create(self.ctx, declContext: self.declContext)
let astNode = withDeclContext(topLevelDecl.asDeclContext) {
body()
func generateTopLevel(codeBlockItem node: CodeBlockItemSyntax) -> BridgedASTNode? {
let parentDC = self.declContext
func maybeTopLevelCodeDecl(body: () -> BridgedASTNode?) -> BridgedASTNode? {
let topLevelDecl: BridgedTopLevelCodeDecl = BridgedTopLevelCodeDecl.create(self.ctx, declContext: self.declContext)
guard let astNode = withDeclContext(topLevelDecl.asDeclContext, body) else {
return nil
}
// Diagnose top level code in non-script file.
if (!declContext.parentSourceFile.isScriptMode) {
switch element.item {
if astNode.kind == .decl {
// If a decl is generated, discard the TopLevelCodeDecl.
return astNode
}
// Diagnose top-level code in non-script files.
if !declContext.parentSourceFile.isScriptMode {
switch astNode.kind {
case .stmt:
self.diagnose(.illegalTopLevelStmt(element))
self.diagnose(.illegalTopLevelStmt(node))
case .expr:
self.diagnose(.illegalTopLevelExpr(element))
self.diagnose(.illegalTopLevelExpr(node))
case .decl:
fatalError("unreachable")
}
}
let bodyRange = self.generateImplicitBraceRange(element)
let bodyRange = self.generateImplicitBraceRange(node)
let body = BridgedBraceStmt.createImplicit(
self.ctx,
lBraceLoc: bodyRange.start,
@@ -100,31 +103,67 @@ struct ASTGenVisitor {
return .decl(topLevelDecl.asDecl)
}
// TODO: Set semicolon loc.
switch element.item {
switch node.item {
case .decl(let node):
if let d = self.generate(decl: node) {
out.append(.decl(d))
if let node = node.as(MacroExpansionDeclSyntax.self) {
return maybeTopLevelCodeDecl {
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
case .generated(let generated):
return generated
case .ignored:
/// If it is actually a macro expansion decl, it should use the parent DC.
return self.withDeclContext(parentDC) {
return .decl(self.generate(macroExpansionDecl: node).asDecl)
}
}
}
}
// Regular 'decl' nodes never be a stmt or expr. No top-level code treatment.
return self.generate(decl: node).map { .decl($0) }
// Hoist 'VarDecl' to the top-level.
withBridgedSwiftClosure { ptr in
let hoisted = ptr!.load(as: BridgedDecl.self)
out.append(.decl(hoisted))
} call: { handle in
d.forEachDeclToHoist(handle)
}
}
case .stmt(let node):
out.append(generateStmtOrExpr {
.stmt(self.generate(stmt: node))
})
case .expr(let node):
out.append(generateStmtOrExpr {
.expr(self.generate(expr: node))
})
return maybeTopLevelCodeDecl {
if let node = node.as(MacroExpansionExprSyntax.self) {
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
case .generated(let generated):
return generated
case .ignored:
// Let regular 'self.generate(expr:)' generate the macro expansions.
break
}
}
return .expr(self.generate(expr: node))
}
case .stmt(let node):
return maybeTopLevelCodeDecl {
return .stmt(self.generate(stmt: node))
}
}
}
func generateTopLevel(codeBlockItemList node: CodeBlockItemListSyntax) -> [BridgedASTNode] {
var out = [BridgedASTNode]()
visitIfConfigElements(
node,
of: CodeBlockItemSyntax.self,
split: Self.splitCodeBlockItemIfConfig
) { element in
guard let item = self.generateTopLevel(codeBlockItem: element) else {
return
}
out.append(item)
// Hoist 'VarDecl' to the block.
if item.kind == .decl {
withBridgedSwiftClosure { ptr in
let d = ptr!.load(as: BridgedDecl.self)
out.append(.decl(d))
} call: { handle in
item.castToDecl().forEachDeclToHoist(handle)
}
}
}
return out
}
}

View File

@@ -0,0 +1,204 @@
//===--- BuiltinPound.swift -----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import ASTBridging
import BasicBridging
@_spi(RawSyntax) import SwiftSyntax
extension ASTGenVisitor {
/// 3 state result:
/// * successfully generated: `.generated(.some(T))`
/// * handled but failed: `.generated(.none)`
/// * fallback to default behavior: `.ignored`
enum MaybeGenerated<T> {
case generated(T?)
case ignored
}
func maybeGenerateBuiltinPound(macroExpansionDecl node: MacroExpansionDeclSyntax) -> MaybeGenerated<BridgedASTNode> {
let result = maybeGenerateBuiltinPound(freestandingMacroExpansion: node)
switch result {
case .generated(_):
guard node.attributes.isEmpty && node.modifiers.isEmpty else {
// TODO: Diagnose.
fatalError("attributes not applied")
}
break
case .ignored:
break
}
return result
}
/// Handle built in pound keywords.
func maybeGenerateBuiltinPound(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> MaybeGenerated<BridgedASTNode> {
let macroNameText = node.macroName.rawText;
// '#file', '#line' etc.
let magicIdentifierKind = BridgedMagicIdentifierLiteralKind(from: macroNameText.bridged)
if magicIdentifierKind != .none {
let magicIdentifierExpr = self.generateMagicIdentifierExpr(
freestandingMacroExpansion: node,
kind: magicIdentifierKind
)
return .generated(.expr(magicIdentifierExpr.asExpr))
}
// '#colorLiteral' et al.
let objectLiteralKind = BridgedObjectLiteralKind(from: macroNameText.bridged)
if objectLiteralKind != .none {
let objectLiteralExpr = self.generateObjectLiteralExpr(
freestandingMacroExpansion: node,
kind: objectLiteralKind
)
return .generated(.expr(objectLiteralExpr.asExpr))
}
// Other built-in pound syntax.
let keyword = BridgedPoundKeyword(from: macroNameText.bridged)
switch keyword {
case .selector:
let selectorExpr = self.generateObjCSelectorExpr(freestandingMacroExpansion: node)
return .generated(.expr(selectorExpr.asExpr))
case .keyPath:
let keypathExpr = self.generateObjCKeyPathExpr(freestandingMacroExpansion: node)
return .generated(.expr(keypathExpr.asExpr))
case .assert where ctx.langOptsHasFeature(.StaticAssert):
let assertStmtOpt = self.generatePoundAssertStmt(freestandingMacroExpansion: node)
return .generated(assertStmtOpt.map({ .stmt($0.asStmt) }))
case .error, .warning:
self.handlePoundDiagnostic(freestandingMacroExpansion: node, kind: keyword == .error ? .error : .warning)
// '#error' and '#warning' don't produce an AST node.
return .generated(nil)
case ._hasSymbol, .available, .unavailable:
// TODO: Diagnose
fatalError("stmt condition outside control flow statement")
// return .generated(nil)
case .none, .assert:
// Not a builtin pound keyword.
return .ignored
case .file, .fileID, .filePath, .function, .line, .column, .dsohandle,
.colorLiteral, .imageLiteral, .fileLiteral:
// Should be handled above
fatalError("(compiler bug) unreachable")
case .if, .elseif, .else, .endif, .sourceLocation:
fatalError("(compiler bug) builtin pound keyword as macro expansion expr")
}
}
enum PoundDiagnosticKind {
case warning, error
}
func handlePoundDiagnostic(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax, kind: PoundDiagnosticKind) {
switch node.parent?.kind {
case .codeBlockItem, .memberBlockItem, nil:
break
default:
// TODO: Diagnose.
fatalError("#error/#warning must be declaration level")
// return
}
guard node.arguments.count == 1,
let arg = node.arguments.first,
arg.label == nil,
let literal = arg.expression.as(StringLiteralExprSyntax.self),
let message = literal.representedLiteralValue
else {
// TODO: Diagnose.
fatalError("expected single simple string literal in #error/#warning")
}
// Unconditionally emit the diagnostic. Inactive #if regions are not generated.
self.diagnose(.poundDiagnostic(literal, message: message, isError: kind == .error))
}
func generatePoundAssertStmt(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedPoundAssertStmt? {
assert(self.ctx.langOptsHasFeature(.StaticAssert))
var args = node.arguments[...]
let conditionExpr = self.generateConsumingAttrOption(args: &args, label: nil) { conditionNode in
self.generate(expr: conditionNode)
}
guard let conditionExpr else {
return nil
}
let message: BridgedStringRef?
if !args.isEmpty {
message = self.generateConsumingSimpleStringLiteralAttrOption(args: &args)
} else {
message = nil
}
return .createParsed(
self.ctx,
range: self.generateSourceRange(node),
condition: conditionExpr,
message: message ?? BridgedStringRef()
)
}
func generateMagicIdentifierExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax, kind: BridgedMagicIdentifierLiteralKind) -> BridgedMagicIdentifierLiteralExpr {
guard node.lastToken(viewMode: .sourceAccurate) == node.macroName else {
// TODO: Diagnose.
fatalError("magic identifier token with arguments")
}
return BridgedMagicIdentifierLiteralExpr.createParsed(
self.ctx,
kind: kind,
loc: self.generateSourceLoc(node.macroName)
)
}
func generateObjectLiteralExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax, kind: BridgedObjectLiteralKind) -> BridgedObjectLiteralExpr {
guard
node.genericArgumentClause == nil,
node.trailingClosure == nil,
node.additionalTrailingClosures.isEmpty
else {
// TODO: Diagnose.
fatalError("object identifier with generic specialization")
}
return BridgedObjectLiteralExpr.createParsed(
self.ctx,
poundLoc: self.generateSourceLoc(node.pound),
kind: kind,
args: self.generateArgumentList(
leftParen: node.leftParen,
labeledExprList: node.arguments,
rightParen: node.rightParen,
trailingClosure: nil,
additionalTrailingClosures: nil
)
)
}
func generateObjCSelectorExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedObjCSelectorExpr {
fatalError("unimplemented")
}
func generateObjCKeyPathExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedKeyPathExpr {
fatalError("unimplemented")
}
}

View File

@@ -3,6 +3,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
ASTGen+CompilerBuildConfiguration.swift
Availability.swift
Bridge.swift
BuiltinPound.swift
CompilerBuildConfiguration.swift
DeclAttrs.swift
Decls.swift

View File

@@ -2201,7 +2201,8 @@ extension ASTGenVisitor {
return extractRawText(segments).bridged
}
// TODO: Diagnose.
return nil
fatalError("expected string literal without interpolation")
// return nil
}
/// Convenient method for processing an attribute with `LabeledExprListSyntax`.

View File

@@ -72,11 +72,6 @@ extension ASTGenVisitor {
}
}
func generate(memberBlockItem node: MemberBlockItemSyntax) -> BridgedDecl? {
// TODO: Set semicolon loc.
generate(decl: node.decl)
}
func generateIdentifierDeclNameAndLoc(_ node: TokenSyntax) -> (identifier: BridgedIdentifier, sourceLoc: BridgedSourceLoc)? {
guard node.presence == .present else {
return nil
@@ -483,7 +478,7 @@ extension ASTGenVisitor {
let brace = BridgedBraceStmt.createParsed(
self.ctx,
lBraceLoc: leftBrace,
elements: self.generate(codeBlockItemList: codeBlock),
elements: self.generate(codeBlockItemList: codeBlock).lazy.bridgedArray(in: self),
rBraceLoc: rightBrace
)
accessor.setParsedBody(brace)
@@ -836,9 +831,16 @@ extension ASTGenVisitor {
extension ASTGenVisitor {
func generate(macroExpansionDecl node: MacroExpansionDeclSyntax) -> BridgedMacroExpansionDecl {
switch self.maybeGenerateBuiltinPound(macroExpansionDecl: node) {
case .generated(_):
fatalError("(compiler bug) builtin pound keywords should be handled elsewhere")
case .ignored:
// Fallback to MacroExpansionDecl.
break
}
let attrs = self.generateDeclAttributes(node, allowStatic: true)
let info = self.generate(freestandingMacroExpansion: node)
let decl = BridgedMacroExpansionDecl.createParsed(
self.declContext,
poundLoc: info.poundLoc,
@@ -1059,6 +1061,29 @@ extension ASTGenVisitor {
}
extension ASTGenVisitor {
func generate(memberBlockItem node: MemberBlockItemSyntax) -> BridgedDecl? {
if let node = node.decl.as(MacroExpansionDeclSyntax.self) {
switch self.maybeGenerateBuiltinPound(macroExpansionDecl: node) {
case .generated(let generated?):
switch generated.kind {
case .decl:
// Actually unreachable as no builtin pound emits a declaration.
return generated.castToDecl()
case .stmt, .expr:
// TODO: Diagnose
fatalError("builtin pound keyword in declaration member block")
//return nil
}
case .generated(nil):
return nil
case .ignored:
// Fallback to normal macro expansion.
break
}
}
return self.generate(decl: node.decl)
}
@inline(__always)
func generate(memberBlockItemList node: MemberBlockItemListSyntax) -> [BridgedDecl] {
var allMembers: [BridgedDecl] = []
@@ -1068,8 +1093,8 @@ extension ASTGenVisitor {
}
return .underlying(element)
} body: { member in
guard let member = self.generate(decl: member.decl) else {
} body: { node in
guard let member = self.generate(memberBlockItem: node) else {
return
}
// TODO: Set semicolon loc.

View File

@@ -165,3 +165,13 @@ extension ASTGenDiagnostic {
)
}
}
extension ASTGenDiagnostic {
static func poundDiagnostic(_ node: StringLiteralExprSyntax, message: String, isError: Bool) -> Self {
Self(
node: node,
message: node.representedLiteralValue!,
severity: isError ? .error : .warning
)
}
}

View File

@@ -388,7 +388,7 @@ extension ASTGenVisitor {
BridgedBraceStmt.createParsed(
self.ctx,
lBraceLoc: self.generateSourceLoc(node.leftBrace),
elements: self.generate(codeBlockItemList: node.statements),
elements: self.generate(codeBlockItemList: node.statements).lazy.bridgedArray(in: self),
rBraceLoc: self.generateSourceLoc(node.rightBrace)
)
}
@@ -847,83 +847,24 @@ extension ASTGenVisitor {
)
}
func generateMagicIdentifierExpr(macroExpansionExpr node: MacroExpansionExprSyntax, kind: BridgedMagicIdentifierLiteralKind) -> BridgedMagicIdentifierLiteralExpr {
guard node.lastToken(viewMode: .sourceAccurate) == node.macroName else {
// TODO: Diagnose.
fatalError("magic identifier token with arguments")
}
return BridgedMagicIdentifierLiteralExpr.createParsed(
self.ctx,
kind: kind,
loc: self.generateSourceLoc(node.macroName)
)
}
func generateObjectLiteralExpr(macroExpansionExpr node: MacroExpansionExprSyntax, kind: BridgedObjectLiteralKind) -> BridgedObjectLiteralExpr {
guard
node.genericArgumentClause == nil,
node.trailingClosure == nil,
node.additionalTrailingClosures.isEmpty
else {
// TODO: Diagnose.
fatalError("object identifier with generic specialization")
}
return BridgedObjectLiteralExpr.createParsed(
self.ctx,
poundLoc: self.generateSourceLoc(node.pound),
kind: kind,
args: self.generateArgumentList(
leftParen: node.leftParen,
labeledExprList: node.arguments,
rightParen: node.rightParen,
trailingClosure: nil,
additionalTrailingClosures: nil
)
)
}
func generateObjCSelectorExpr(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedObjCSelectorExpr {
fatalError("unimplemented")
}
func generateObjCKeyPathExpr(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedKeyPathExpr {
fatalError("unimplemented")
}
func generate(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedExpr {
let macroNameText = node.macroName.rawText;
// '#file', '#line' etc.
let magicIdentifierKind = BridgedMagicIdentifierLiteralKind(from: macroNameText.bridged)
if magicIdentifierKind != .none {
return self.generateMagicIdentifierExpr(
macroExpansionExpr: node,
kind: magicIdentifierKind
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
case .generated(let astNode):
guard let astNode else {
return BridgedErrorExpr.create(
self.ctx,
loc: self.generateSourceRange(node)
).asExpr
}
// '#colorLiteral' et al.
let objectLiteralKind = BridgedObjectLiteralKind(from: macroNameText.bridged)
if objectLiteralKind != .none {
return self.generateObjectLiteralExpr(
macroExpansionExpr: node,
kind: objectLiteralKind
).asExpr
switch astNode.kind {
case .expr:
return astNode.castToExpr()
case .stmt, .decl:
// TODO: Diagnose
fatalError("builtin pound directive in expression position")
// return BridgedErrorExpr.create(...)
}
// Other built-in pound expressions.
switch macroNameText {
case "selector":
return self.generateObjCSelectorExpr(macroExpansionExpr: node).asExpr
case "keyPath":
return self.generateObjCKeyPathExpr(macroExpansionExpr: node).asExpr
case "assert" where ctx.langOptsHasFeature(.StaticAssert), "error", "warning":
// TODO: Diagnose.
fatalError("Directives in expression position");
default:
case .ignored:
// Fallback to MacroExpansionExpr.
break
}

View File

@@ -12,7 +12,7 @@
import ASTBridging
import SwiftDiagnostics
@_spi(ExperimentalLanguageFeatures) import SwiftSyntax
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax
protocol DoStmtOrExprSyntax {
var doKeyword: TokenSyntax { get }
@@ -70,16 +70,34 @@ extension ASTGenVisitor {
// TODO: Set semicolon loc.
switch node.item {
case .decl(let node):
if let node = node.as(MacroExpansionDeclSyntax.self) {
switch self.maybeGenerateBuiltinPound(macroExpansionDecl: node) {
case .generated(let generated):
return generated
case .ignored:
// Fallback to normal macro expansion.
break
}
}
return self.generate(decl: node).map { .decl($0) }
case .stmt(let node):
return .stmt(self.generate(stmt: node))
case .expr(let node):
if let node = node.as(MacroExpansionExprSyntax.self) {
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
case .generated(let generated):
return generated
case .ignored:
// Fallback to normal macro expansion.
break
}
}
return .expr(self.generate(expr: node))
}
}
@inline(__always)
func generate(codeBlockItemList node: CodeBlockItemListSyntax) -> BridgedArrayRef {
func generate(codeBlockItemList node: CodeBlockItemListSyntax) -> [BridgedASTNode] {
var allItems: [BridgedASTNode] = []
visitIfConfigElements(
node,
@@ -102,7 +120,7 @@ extension ASTGenVisitor {
}
}
return allItems.lazy.bridgedArray(in: self)
return allItems
}
/// Function that splits a code block item into either an #if or the item.
@@ -121,19 +139,47 @@ extension ASTGenVisitor {
BridgedBraceStmt.createParsed(
self.ctx,
lBraceLoc: self.generateSourceLoc(node.leftBrace),
elements: self.generate(codeBlockItemList: node.statements),
elements: self.generate(codeBlockItemList: node.statements).lazy.bridgedArray(in: self),
rBraceLoc: self.generateSourceLoc(node.rightBrace)
)
}
func generateHasSymbolStmtCondition(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedStmtConditionElement {
var args = node.arguments[...]
let symbol: BridgedExpr?
if let arg = args.popFirst() {
symbol = self.generate(expr: arg.expression)
if arg.label != nil {
// TODO: Diagnose
fatalError("unexpected label")
}
if !args.isEmpty {
// TODO: Diagnose
fatalError("extra args")
}
} else {
symbol = nil
}
return .createHasSymbol(
self.ctx,
poundLoc: self.generateSourceLoc(node.pound),
lParenLoc: self.generateSourceLoc(node.leftParen),
symbol: symbol.asNullable,
rParenLoc: self.generateSourceLoc(node.rightParen)
)
}
func generate(conditionElement node: ConditionElementSyntax) -> BridgedStmtConditionElement {
// FIXME: _hasSymbol is not implemented in SwiftSyntax/SwiftParser.
switch node.condition {
case .availability(let node):
return .createPoundAvailable(
info: self.generate(availabilityCondition: node)
)
case .expression(let node):
if let node = node.as(MacroExpansionExprSyntax.self),
node.macroName.rawText == "_hasSymbol" {
return generateHasSymbolStmtCondition(macroExpansionExpr: node)
}
return .createBoolean(
expr: self.generate(expr: node)
)
@@ -487,7 +533,7 @@ extension ASTGenVisitor {
let body = BridgedBraceStmt.createParsed(
self.ctx,
lBraceLoc: nil,
elements: self.generate(codeBlockItemList: node.statements),
elements: self.generate(codeBlockItemList: node.statements).lazy.bridgedArray(in: self),
rBraceLoc: nil
)

View File

@@ -58,5 +58,7 @@ func testPoundIf() {
// pass
} else if #unavailable(macOS 80) {
// pass
} else if #_hasSymbol(Int.self) { // expected-warning {{struct 'Int' is not a weakly linked declaration}}
// pass
}
}

View File

@@ -36,3 +36,18 @@ struct S {
struct ExpansionRequirementTest<each T> {}
extension ExpansionRequirementTest where repeat each T == Int {} // expected-error {{same-element requirements are not yet supported}}
#warning("this is a warning") // expected-warning {{this is a warning}}
func testDiagnosticInFunc() {
#error("this is an error") // expected-error {{this is an error}}
}
class TestDiagnosticInNominalTy {
#error("this is an error member") // expected-error {{this is an error member}}
}
#if FLAG_NOT_ENABLED
#error("error in inactive") // no diagnostis
#endif

View File

@@ -0,0 +1,21 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend-dump-parse -enable-experimental-feature ParserASTGen \
// RUN: -enable-experimental-feature StaticAssert \
// RUN: | %sanitize-address > %t/astgen.ast
// RUN: %target-swift-frontend-dump-parse \
// RUN: -enable-experimental-feature StaticAssert \
// RUN: | %sanitize-address > %t/cpp-parser.ast
// RUN: %diff -u %t/astgen.ast %t/cpp-parser.ast
// RUN: %target-swift-emit-sil -verify %s -enable-experimental-feature ParserASTGen \
// RUN: -enable-experimental-feature StaticAssert
// REQUIRES: swift_swift_parser
// REQUIRES: swift_feature_ParserASTGen
// REQUIRES: swift_feature_StaticAssert
func testPoundAssert() {
#assert(1 == 1.0, "1 must be 1.0") // OK
#assert(1 == 1.5, "1 is 1.5 ??") // expected-error {{1 is 1.5 ??}}
}