Skip to content

Commit 3616872

Browse files
authored
Merge pull request #39068 from nkcsgexi/73902734
ClangImporter: teach clang importer to import Clang SPI symbols and model them similarly as Swift SPIs
2 parents 8b32792 + 36f25c3 commit 3616872

File tree

8 files changed

+95
-1
lines changed

8 files changed

+95
-1
lines changed

include/swift/Strings.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ constexpr static const StringLiteral DEFAULT_ACTOR_STORAGE_FIELD_NAME =
5858
/// The name of the Builtin type prefix
5959
constexpr static const StringLiteral BUILTIN_TYPE_NAME_PREFIX = "Builtin.";
6060

61+
/// The default SPI group name to associate with Clang SPIs.
62+
constexpr static const StringLiteral CLANG_MODULE_DEFUALT_SPI_GROUP_NAME =
63+
"OBJC_DEFAULT_SPI_GROUP";
64+
6165
/// A composition class containing a StringLiteral for the names of
6266
/// Swift builtins. The reason we use this is to ensure that we when
6367
/// necessary slice off the "Builtin." prefix from these names in a

lib/ClangImporter/ImportDecl.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8544,6 +8544,21 @@ Optional<bool> swift::importer::isMainActorAttr(
85448544
return None;
85458545
}
85468546

8547+
static bool isUsingMacroName(clang::SourceManager &SM,
8548+
clang::SourceLocation loc,
8549+
StringRef MacroName) {
8550+
if (!loc.isMacroID())
8551+
return false;
8552+
auto Sloc = SM.getExpansionLoc(loc);
8553+
if (Sloc.isInvalid())
8554+
return false;
8555+
auto Eloc = Sloc.getLocWithOffset(MacroName.size());
8556+
if (Eloc.isInvalid())
8557+
return false;
8558+
StringRef content(SM.getCharacterData(Sloc), MacroName.size());
8559+
return content == MacroName;
8560+
}
8561+
85478562
/// Import Clang attributes as Swift attributes.
85488563
void ClangImporter::Implementation::importAttributes(
85498564
const clang::NamedDecl *ClangDecl,
@@ -8667,6 +8682,17 @@ void ClangImporter::Implementation::importAttributes(
86678682
AnyUnavailable = true;
86688683
}
86698684

8685+
if (isUsingMacroName(getClangASTContext().getSourceManager(),
8686+
avail->getLoc(), "SPI_AVAILABLE") ||
8687+
isUsingMacroName(getClangASTContext().getSourceManager(),
8688+
avail->getLoc(), "__SPI_AVAILABLE")) {
8689+
// The decl has been marked as SPI in the header by using the SPI macro,
8690+
// thus we add the SPI attribute to it with a default group name.
8691+
MappedDecl->getAttrs().add(SPIAccessControlAttr::create(SwiftContext,
8692+
SourceLoc(), SourceRange(),
8693+
SwiftContext.getIdentifier(CLANG_MODULE_DEFUALT_SPI_GROUP_NAME)));
8694+
}
8695+
86708696
StringRef message = avail->getMessage();
86718697

86728698
llvm::VersionTuple deprecated = avail->getDeprecated();

lib/ClangImporter/ImporterImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
642642

643643
/// The DWARF importer delegate, if installed.
644644
DWARFImporterDelegate *DWARFImporter = nullptr;
645+
645646
public:
646647
/// Only used for testing.
647648
void setDWARFImporterDelegate(DWARFImporterDelegate &delegate);

lib/Sema/ImportResolution.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/ClangImporter/ClangModule.h"
2929
#include "swift/Parse/Parser.h"
3030
#include "swift/Subsystems.h"
31+
#include "swift/Strings.h"
3132
#include "clang/Basic/Module.h"
3233
#include "llvm/ADT/DenseMap.h"
3334
#include "llvm/ADT/TinyPtrVector.h"
@@ -317,6 +318,23 @@ void ImportResolver::bindImport(UnboundImport &&I) {
317318
ID.get()->setModule(nullptr);
318319
return;
319320
}
321+
// If the imported module is a clang module, add an implicit import statement
322+
// to request the SPIs from the module.
323+
if (M->isNonSwiftModule() && ID &&
324+
!ID.get()->getAttrs().hasAttribute<SPIAccessControlAttr>()) {
325+
ImportDecl *id = ID.get();
326+
auto *newId = ImportDecl::create(id->getASTContext(), id->getDeclContext(),
327+
SourceLoc(), id->getImportKind(), SourceLoc(), id->getImportPath());
328+
// Copy all the existing attribute from the actual import statement.
329+
llvm::for_each(id->getAttrs(),
330+
[&](DeclAttribute *attr) {newId->getAttrs().add(attr);});
331+
// Add SPI attribute with the default group name.
332+
newId->getAttrs().add(SPIAccessControlAttr::create(id->getASTContext(),
333+
SourceLoc(), SourceRange(),
334+
{ ctx.getIdentifier(CLANG_MODULE_DEFUALT_SPI_GROUP_NAME) }));
335+
// So we'll resolve the new import.
336+
unboundImports.push_back(UnboundImport(newId));
337+
}
320338

321339
auto topLevelModule = I.getTopLevelModule(M, SF);
322340

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#import <Foundation/Foundation.h>
2+
3+
#ifdef SPI_AVAILABLE
4+
#undef SPI_AVAILABLE
5+
#define SPI_AVAILABLE API_AVAILABLE
6+
#endif
7+
8+
#ifdef __SPI_AVAILABLE
9+
#undef __SPI_AVAILABLE
10+
#define __SPI_AVAILABLE API_AVAILABLE
11+
#endif
12+
13+
SPI_AVAILABLE(macos(10.7))
14+
@interface SPIInterface1
15+
@end
16+
17+
__SPI_AVAILABLE(macos(10.7))
18+
@interface SPIInterface2
19+
@end
20+
21+
@interface SharedInterface
22+
+ (NSInteger)foo SPI_AVAILABLE(macos(10.7));
23+
@end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
framework module SPIContainer {
2+
umbrella header "SPIContainer.h"
3+
export *
4+
module * {
5+
export *
6+
}
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// REQUIRES: OS=macosx
2+
// RUN: %target-swift-frontend -typecheck %s -F %S/Inputs/frameworks -verify
3+
4+
import SPIContainer
5+
6+
@_spi(a) public let a: SPIInterface1
7+
@_spi(a) public let b: SPIInterface2
8+
9+
public let c: SPIInterface1 // expected-error{{cannot use class 'SPIInterface1' here; it is an SPI imported from 'SPIContainer'}}
10+
public let d: SPIInterface2 // expected-error{{cannot use class 'SPIInterface2' here; it is an SPI imported from 'SPIContainer'}}
11+
12+
@inlinable
13+
public func inlinableUsingSPI() {
14+
SharedInterface.foo() // expected-error{{class method 'foo()' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIContainer'}}
15+
}

validation-test/Serialization/bridging-header-first.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// CHECK-DUMP: IMPORTED_MODULE
1919
// CHECK-DUMP-SAME: 'Module'
2020
// CHECK-DUMP: IMPORTED_MODULE
21-
// CHECK-DUMP-SAME: 'Swift'
21+
// CHECK-DUMP: 'Swift'
2222

2323

2424
import Module

0 commit comments

Comments
 (0)