Skip to content

Commit 0d19b78

Browse files
committed
Use the SwiftIfConfig library for evaluating #if conditions.
Replace the C++ implementation of #if condition operator folding, validation, and evaluation with the corresponding facilities in the SwiftIfConfig library. Leave the C++ implementation in place for now to permit the compiler to continue building without swift-syntax.
1 parent 2b2b763 commit 0d19b78

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ struct CompilerBuildConfiguration: BuildConfiguration {
9898

9999
func isActiveTargetRuntime(name: String) throws -> Bool {
100100
var name = name
101+
102+
// Complain if the provided runtime isn't one of the known values.
103+
switch name {
104+
case "_Native", "_ObjC", "_multithreaded": break
105+
default: throw IfConfigError.unexpectedRuntimeCondition
106+
}
107+
101108
return name.withBridgedString { nameRef in
102109
ctx.langOptsIsActiveTargetRuntime(nameRef)
103110
}
@@ -150,6 +157,18 @@ struct CompilerBuildConfiguration: BuildConfiguration {
150157
}
151158
}
152159

160+
enum IfConfigError: Error, CustomStringConvertible {
161+
case unexpectedRuntimeCondition
162+
163+
var description: String {
164+
switch self {
165+
case .unexpectedRuntimeCondition:
166+
return "unexpected argument for the '_runtime' condition; expected '_Native' or '_ObjC'"
167+
}
168+
}
169+
}
170+
171+
153172
/// Extract the #if clause range information for the given source file.
154173
@_cdecl("swift_ASTGen_configuredRegions")
155174
public func configuredRegions(
@@ -290,3 +309,53 @@ public func freeConfiguredRegions(
290309
) {
291310
UnsafeMutableBufferPointer(start: regions, count: numRegions).deallocate()
292311
}
312+
313+
/// Evaluate the #if condition at ifClauseLocationPtr.
314+
@_cdecl("swift_ASTGen_evaluatePoundIfCondition")
315+
public func evaluatePoundIfCondition(
316+
astContext: BridgedASTContext,
317+
diagEnginePtr: UnsafeMutableRawPointer,
318+
sourceFileBuffer: BridgedStringRef,
319+
ifConditionText: BridgedStringRef,
320+
shouldEvaluate: Bool
321+
) -> Int {
322+
// Retrieve the #if condition that we're evaluating here.
323+
// FIXME: Use 'ExportedSourceFile' when C++ parser is replaced.
324+
let textBuffer = UnsafeBufferPointer<UInt8>(start: ifConditionText.data, count: ifConditionText.count)
325+
var parser = Parser(textBuffer)
326+
let conditionExpr = ExprSyntax.parse(from: &parser)
327+
328+
let isActive: Bool
329+
let syntaxErrorsAllowed: Bool
330+
let diagnostics: [Diagnostic]
331+
if shouldEvaluate {
332+
// Evaluate the condition against the compiler's build configuration.
333+
let configuration = CompilerBuildConfiguration(
334+
ctx: astContext,
335+
conditionLoc: BridgedSourceLoc(raw: ifConditionText.data)
336+
)
337+
338+
let state: IfConfigRegionState
339+
(state, syntaxErrorsAllowed, diagnostics) = IfConfigRegionState.evaluating(conditionExpr, in: configuration)
340+
isActive = (state == .active)
341+
} else {
342+
// Don't evaluate the condition, because we know it's inactive. Determine
343+
// whether syntax errors are permitted within this region according to the
344+
// condition.
345+
isActive = false
346+
(syntaxErrorsAllowed, diagnostics) = IfConfigClauseSyntax.syntaxErrorsAllowed(conditionExpr)
347+
}
348+
349+
// Render the diagnostics.
350+
for diagnostic in diagnostics {
351+
emitDiagnostic(
352+
diagnosticEngine: BridgedDiagnosticEngine(raw: diagEnginePtr),
353+
sourceFileBuffer: UnsafeBufferPointer(start: sourceFileBuffer.data, count: sourceFileBuffer.count),
354+
sourceFileBufferOffset: ifConditionText.data! - sourceFileBuffer.data!,
355+
diagnostic: diagnostic,
356+
diagnosticSeverity: diagnostic.diagMessage.severity
357+
)
358+
}
359+
360+
return (isActive ? 0x1 : 0) | (syntaxErrorsAllowed ? 0x2 : 0)
361+
}

lib/Parse/ParseIfConfig.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "swift/Parse/Parser.h"
1818

19+
#include "swift/AST/ASTBridging.h"
1920
#include "swift/AST/ASTVisitor.h"
2021
#include "swift/AST/DiagnosticSuppression.h"
2122
#include "swift/Basic/Assertions.h"
@@ -766,6 +767,44 @@ static Expr *findAnyLikelySimulatorEnvironmentTest(Expr *Condition) {
766767

767768
} // end anonymous namespace
768769

770+
extern "C" intptr_t swift_ASTGen_evaluatePoundIfCondition(
771+
BridgedASTContext astContext,
772+
void *_Nonnull diagEngine,
773+
BridgedStringRef sourceFileBuffer,
774+
BridgedStringRef conditionText,
775+
bool);
776+
777+
/// Call into the Swift implementation of #if condition evaluation.
778+
///
779+
/// \returns std::nullopt if the Swift implementation is not available, or
780+
/// a pair (isActive, allowSyntaxErrors) describing whether the evaluated
781+
/// condition indicates that the region is active and whether, if inactive,
782+
/// the code in that region is allowed to have syntax errors.
783+
static std::optional<std::pair<bool, bool>> evaluateWithSwiftIfConfig(
784+
Parser &parser,
785+
SourceRange conditionRange,
786+
bool shouldEvaluate
787+
) {
788+
#if SWIFT_BUILD_SWIFT_SYNTAX
789+
// FIXME: When we migrate to SwiftParser, use the parsed syntax tree.
790+
auto &sourceMgr = parser.Context.SourceMgr;
791+
StringRef sourceFileText =
792+
sourceMgr.getEntireTextForBuffer(*parser.SF.getBufferID());
793+
StringRef conditionText =
794+
sourceMgr.extractText(Lexer::getCharSourceRangeFromSourceRange(
795+
sourceMgr, conditionRange));
796+
intptr_t evalResult = swift_ASTGen_evaluatePoundIfCondition(
797+
parser.Context, &parser.Context.Diags, sourceFileText, conditionText,
798+
shouldEvaluate
799+
);
800+
801+
bool isActive = (evalResult & 0x01) != 0;
802+
bool allowSyntaxErrors = (evalResult & 0x02) != 0;
803+
return std::pair(isActive, allowSyntaxErrors);
804+
#else
805+
return std::nullopt;
806+
#endif
807+
}
769808

770809
/// Parse and populate a #if ... #endif directive.
771810
/// Delegate callback function to parse elements in the blocks.
@@ -842,7 +881,15 @@ Result Parser::parseIfConfigRaw(
842881
if (result.isNull())
843882
return makeParserError();
844883
Condition = result.get();
845-
if (validateIfConfigCondition(Condition, Context, Diags)) {
884+
if (std::optional<std::pair<bool, bool>> evalResult =
885+
evaluateWithSwiftIfConfig(*this,
886+
Condition->getSourceRange(),
887+
shouldEvaluate)) {
888+
if (!foundActive) {
889+
isActive = evalResult->first;
890+
isVersionCondition = evalResult->second;
891+
}
892+
} else if (validateIfConfigCondition(Condition, Context, Diags)) {
846893
// Error in the condition;
847894
isActive = false;
848895
isVersionCondition = false;

0 commit comments

Comments
 (0)