Skip to content

Commit 865c643

Browse files
committed
Suppress Embedded Restriction diagnostics in code that won't be compiled as Embedded
When emitting diagnostics for the Embedded Swift restrictions outside of Embedded Swift mode, consider `#if $Embedded` and `#if hasFeature(Embedded)` configurations. If the code where we would emit the diagnostic would be disabled in Embedded Swift by one of those checks, don't emit the diagnostic. This helps code that can compile either with Embedded or regular Swift stay within the restrictions on Embedded Swift.
1 parent 7d21bc3 commit 865c643

File tree

6 files changed

+192
-0
lines changed

6 files changed

+192
-0
lines changed

include/swift/Bridging/ASTGen.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ intptr_t swift_ASTGen_configuredRegions(
117117
void swift_ASTGen_freeConfiguredRegions(
118118
BridgedIfConfigClauseRangeInfo *_Nullable regions, intptr_t numRegions);
119119

120+
intptr_t swift_ASTGen_activeInEmbeddedSwift(
121+
BridgedASTContext astContext,
122+
void *_Nonnull sourceFile,
123+
swift::SourceLoc location);
124+
120125
bool swift_ASTGen_validateUnqualifiedLookup(
121126
void *_Nonnull sourceFile,
122127
BridgedASTContext astContext,

lib/ASTGen/Sources/ASTGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
99
Decls.swift
1010
Diagnostics.swift
1111
DiagnosticsBridge.swift
12+
EmbeddedSupport.swift
1213
Exprs.swift
1314
Fingerprint.swift
1415
Generics.swift
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===--- EmbeddedSupport.swift --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022-2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ASTBridging
14+
import BasicBridging
15+
import SwiftIfConfig
16+
import SwiftSyntax
17+
18+
extension ExportedSourceFile {
19+
/// Return the configured regions for this source file.
20+
mutating func configuredRegionsIfEmbedded(astContext: BridgedASTContext) -> ConfiguredRegions {
21+
if let _configuredRegionsIfEmbedded {
22+
return _configuredRegionsIfEmbedded
23+
}
24+
25+
// Ensure that we've already computed the configured regions, which can
26+
// emit diagnostics.
27+
_ = configuredRegions(astContext: astContext)
28+
29+
let configuration = EmbeddedBuildConfiguration(
30+
ctx: astContext,
31+
sourceBuffer: buffer
32+
)
33+
34+
let regions = syntax.configuredRegions(in: configuration)
35+
_configuredRegionsIfEmbedded = regions
36+
return regions
37+
}
38+
}
39+
40+
/// Determine whether the given source location is active when this source
41+
/// file is compiled in Embedded Swift.
42+
@_cdecl("swift_ASTGen_activeInEmbeddedSwift")
43+
public func activeInEmbeddedSwift(
44+
astContext: BridgedASTContext,
45+
sourceFilePtr: UnsafeMutableRawPointer,
46+
at location: SourceLoc
47+
) -> Int {
48+
guard let token = findToken(
49+
in: UnsafeRawPointer(sourceFilePtr),
50+
at: location.raw?.assumingMemoryBound(to: UInt8.self)
51+
) else {
52+
return 0
53+
}
54+
55+
let sourceFile = sourceFilePtr.assumingMemoryBound(to: ExportedSourceFile.self)
56+
let regions = sourceFile.pointee.configuredRegionsIfEmbedded(astContext: astContext)
57+
return regions.isActive(token) == .active ? 1 : 0
58+
}
59+
60+
/// A build configuration that is a thin shim over the
61+
/// CompilerBuildConfiguration that enables the Embedded language feature,
62+
/// allowing the compiler to determine whether code we're in will be available
63+
/// in an embedded context or not.
64+
struct EmbeddedBuildConfiguration: BuildConfiguration {
65+
let configuration: CompilerBuildConfiguration
66+
67+
init(ctx: BridgedASTContext, sourceBuffer: UnsafeBufferPointer<UInt8>) {
68+
self.configuration = .init(ctx: ctx, sourceBuffer: sourceBuffer)
69+
}
70+
71+
func isCustomConditionSet(name: String) throws -> Bool {
72+
// $Embedded is set when building Embedded Swift
73+
if name == "$Embedded" {
74+
return true
75+
}
76+
77+
return try configuration.isCustomConditionSet(name: name)
78+
}
79+
80+
func hasFeature(name: String) throws -> Bool {
81+
// The "Embedded" feature is set when building Embedded Swift.
82+
if name == "Embedded" {
83+
return true
84+
}
85+
86+
return try configuration.hasFeature(name: name)
87+
}
88+
89+
func hasAttribute(name: String) throws -> Bool {
90+
return try configuration.hasAttribute(name: name)
91+
}
92+
93+
func canImport(
94+
importPath: [(TokenSyntax, String)],
95+
version: CanImportVersion
96+
) throws -> Bool {
97+
// FIXME: We would prefer to call the underlying canImport in some kind of
98+
// "replay" mode that is not allowed to produce diagnostics or trigger any
99+
// loading.
100+
return false
101+
}
102+
103+
func isActiveTargetOS(name: String) throws -> Bool {
104+
return try configuration.isActiveTargetOS(name: name)
105+
}
106+
107+
func isActiveTargetArchitecture(name: String) throws -> Bool {
108+
return try configuration.isActiveTargetArchitecture(name: name)
109+
}
110+
111+
func isActiveTargetEnvironment(name: String) throws -> Bool {
112+
return try configuration.isActiveTargetEnvironment(name: name)
113+
}
114+
115+
func isActiveTargetRuntime(name: String) throws -> Bool {
116+
return try configuration.isActiveTargetRuntime(name: name)
117+
}
118+
119+
func isActiveTargetPointerAuthentication(name: String) throws -> Bool {
120+
return try configuration.isActiveTargetPointerAuthentication(name: name)
121+
}
122+
123+
var targetPointerBitWidth: Int {
124+
return configuration.targetPointerBitWidth
125+
}
126+
127+
var targetAtomicBitWidths: [Int] {
128+
return configuration.targetAtomicBitWidths
129+
}
130+
131+
var endianness: Endianness {
132+
return configuration.endianness
133+
}
134+
135+
var languageVersion: VersionTuple {
136+
return configuration.languageVersion
137+
}
138+
139+
var compilerVersion: VersionTuple {
140+
return configuration.compilerVersion
141+
}
142+
}

lib/ASTGen/Sources/ASTGen/SourceFile.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ public struct ExportedSourceFile {
4343
/// This is a cached value; access via configuredRegions(astContext:).
4444
var _configuredRegions: ConfiguredRegions? = nil
4545

46+
/// Configured regions for this source file assuming if it were being treated
47+
/// as Embedded Swift. This is used only when we are compiling non-Embedded
48+
/// Swift but diagnosing uses of constructs that aren't allowed in Embedded
49+
/// Swift.
50+
///
51+
/// This is a cached value; access via configuredRegionsAsEmbedded(astContext:).
52+
var _configuredRegionsIfEmbedded: ConfiguredRegions? = nil
53+
4654
public func position(of location: SourceLoc) -> AbsolutePosition? {
4755
let sourceFileBaseAddress = UnsafeRawPointer(buffer.baseAddress!)
4856
guard let rawAddress = location.raw else {

lib/Sema/TypeCheckEmbedded.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
#include "swift/AST/Decl.h"
2020
#include "swift/AST/DiagnosticsSema.h"
2121
#include "swift/AST/Effects.h"
22+
#include "swift/AST/SourceFile.h"
2223
#include "swift/AST/Types.h"
24+
#include "swift/Basic/SourceLoc.h"
25+
#include "swift/Bridging/ASTGen.h"
2326

2427
using namespace swift;
2528

@@ -40,6 +43,20 @@ swift::shouldDiagnoseEmbeddedLimitations(const DeclContext *dc, SourceLoc loc,
4043
if (diags.isIgnoredDiagnostic(diag::untyped_throws_in_embedded_swift.ID))
4144
return std::nullopt;
4245

46+
#if SWIFT_BUILD_SWIFT_SYNTAX
47+
// If we are not in Embedded Swift, check whether the location we are
48+
// diagnosing at is likely to be active when compiling Embedded Swift. If not,
49+
// suppress the diagnostic.
50+
auto sourceFile = dc->getParentSourceFile();
51+
if (!dc->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
52+
sourceFile &&
53+
!swift_ASTGen_activeInEmbeddedSwift(sourceFile->getASTContext(),
54+
sourceFile->getExportedSourceFile(),
55+
loc)) {
56+
return std::nullopt;
57+
}
58+
#endif
59+
4360
// If this was always an error in Embedded Swift, we aren't in Embedded Swift
4461
// now, so downgrade to a warning.
4562
if (wasAlwaysEmbeddedError)

test/embedded/restrictions.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,22 @@ public struct MyStruct {
6363

6464
unowned(unsafe) var unownedUnsafe: MyClass
6565
}
66+
67+
// ---------------------------------------------------------------------------
68+
// #if handling to suppress diagnostics for non-Embedded-only code
69+
// ---------------------------------------------------------------------------
70+
71+
#if $Embedded
72+
73+
// expected-embedded-warning@+1{{untyped throws is not available in Embedded Swift; add a thrown error type with '(type)'}}{{31-31=(<#thrown error type#>)}}
74+
func stillProblematic() throws { }
75+
76+
#else
77+
78+
func notProblematicAtAll() throws { }
79+
80+
#endif
81+
82+
#if !hasFeature(Embedded)
83+
func stillNotProblematicAtAll() throws { }
84+
#endif

0 commit comments

Comments
 (0)