[cxx-interop] Remove symbolic import mode

Importing C++ class templates in symbolic mode has proven to be problematic in interaction with other compiler features, and it isn't used widely. This change removes the feature.

rdar://150528798
This commit is contained in:
Egor Zhdan
2025-05-02 18:43:09 +01:00
parent 9de2419153
commit b51cfa5c76
20 changed files with 14 additions and 857 deletions

View File

@@ -376,11 +376,6 @@ EXPERIMENTAL_FEATURE(ParserASTGen, false)
/// corresponding syntax tree.
EXPERIMENTAL_FEATURE(BuiltinMacros, false)
/// Import C++ class templates as semantically-meaningless symbolic
/// Swift types and C++ methods as symbolic functions with blank
/// signatures.
EXPERIMENTAL_FEATURE(ImportSymbolicCXXDecls, false)
/// Generate bindings for functions that 'throw' in the C++ section of the generated Clang header.
EXPERIMENTAL_FEATURE(GenerateBindingsForThrowingFunctionsInCXX, false)

View File

@@ -690,12 +690,6 @@ public:
/// of the provided baseType.
void diagnoseMemberValue(const DeclName &name, const Type &baseType) override;
/// Enable the symbolic import experimental feature for the given callback.
void withSymbolicFeatureEnabled(llvm::function_ref<void(void)> callback);
/// Returns true when the symbolic import experimental feature is enabled.
bool isSymbolicImportEnabled() const;
const clang::TypedefType *getTypeDefForCXXCFOptionsDefinition(
const clang::Decl *candidateDecl) override;

View File

@@ -109,7 +109,6 @@ UNINTERESTING_FEATURE(UnqualifiedLookupValidation)
UNINTERESTING_FEATURE(ImplicitSome)
UNINTERESTING_FEATURE(ParserASTGen)
UNINTERESTING_FEATURE(BuiltinMacros)
UNINTERESTING_FEATURE(ImportSymbolicCXXDecls)
UNINTERESTING_FEATURE(GenerateBindingsForThrowingFunctionsInCXX)
UNINTERESTING_FEATURE(ReferenceBindings)
UNINTERESTING_FEATURE(BuiltinModule)

View File

@@ -2726,8 +2726,6 @@ ClangImporter::Implementation::Implementation(
DisableOverlayModules(ctx.ClangImporterOpts.DisableOverlayModules),
EnableClangSPI(ctx.ClangImporterOpts.EnableClangSPI),
UseClangIncludeTree(ctx.ClangImporterOpts.UseClangIncludeTree),
importSymbolicCXXDecls(
ctx.LangOpts.hasFeature(Feature::ImportSymbolicCXXDecls)),
IsReadingBridgingPCH(false),
CurrentVersion(ImportNameVersion::fromOptions(ctx.LangOpts)),
Walker(DiagnosticWalker(*this)), BuffersForDiagnostics(ctx.SourceMgr),
@@ -8569,23 +8567,6 @@ bool ClangDeclExplicitSafety::isCached() const {
return isa<clang::RecordDecl>(std::get<0>(getStorage()).decl);
}
void ClangImporter::withSymbolicFeatureEnabled(
llvm::function_ref<void(void)> callback) {
llvm::SaveAndRestore<bool> oldImportSymbolicCXXDecls(
Impl.importSymbolicCXXDecls, true);
Impl.nameImporter->enableSymbolicImportFeature(true);
auto importedDeclsCopy = Impl.ImportedDecls;
Impl.ImportedDecls.clear();
callback();
Impl.ImportedDecls = std::move(importedDeclsCopy);
Impl.nameImporter->enableSymbolicImportFeature(
oldImportSymbolicCXXDecls.get());
}
bool ClangImporter::isSymbolicImportEnabled() const {
return Impl.importSymbolicCXXDecls;
}
const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
const clang::Decl *candidateDecl) {

View File

@@ -2141,8 +2141,7 @@ namespace {
}
// TODO(https://github.com/apple/swift/issues/56206): Fix this once we support dependent types.
if (decl->getTypeForDecl()->isDependentType() &&
!Impl.importSymbolicCXXDecls) {
if (decl->getTypeForDecl()->isDependentType()) {
Impl.addImportDiagnostic(
decl, Diagnostic(
diag::record_is_dependent,
@@ -3068,11 +3067,8 @@ namespace {
auto semanticsKind = evaluateOrDefault(
Impl.SwiftContext.evaluator,
CxxRecordSemantics({decl, Impl.SwiftContext, &Impl}), {});
if ((semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation ||
semanticsKind == CxxRecordSemanticsKind::UnavailableConstructors) &&
// Let un-specialized class templates through. We'll sort out their
// members once they're instantiated.
!Impl.importSymbolicCXXDecls) {
if (semanticsKind == CxxRecordSemanticsKind::MissingLifetimeOperation ||
semanticsKind == CxxRecordSemanticsKind::UnavailableConstructors) {
HeaderLoc loc(decl->getLocation());
if (hasUnsafeAPIAttr(decl))
@@ -3267,12 +3263,6 @@ namespace {
Decl *VisitClassTemplateSpecializationDecl(
const clang::ClassTemplateSpecializationDecl *decl) {
// Treat a specific specialization like the unspecialized class template
// when importing it in symbolic mode.
if (Impl.importSymbolicCXXDecls)
return Impl.importDecl(decl->getSpecializedTemplate(),
Impl.CurrentVersion);
bool isPair = decl->getSpecializedTemplate()->isInStdNamespace() &&
decl->getSpecializedTemplate()->getName() == "pair";
@@ -3953,8 +3943,6 @@ namespace {
Impl.SwiftContext, SourceLoc(), templateParams, SourceLoc());
}
bool importFuncWithoutSignature =
isa<clang::CXXMethodDecl>(decl) && Impl.importSymbolicCXXDecls;
if (!dc->isModuleScopeContext() && !isClangNamespace(dc) &&
!isa<clang::CXXMethodDecl>(decl)) {
// Handle initializers.
@@ -4021,39 +4009,12 @@ namespace {
importedType =
Impl.importFunctionReturnType(dc, decl, allowNSUIntegerAsInt);
} else {
if (importFuncWithoutSignature) {
importedType = ImportedType{Impl.SwiftContext.getVoidType(), false};
if (decl->param_empty())
bodyParams = ParameterList::createEmpty(Impl.SwiftContext);
else {
llvm::SmallVector<ParamDecl *, 4> params;
for (const auto &param : decl->parameters()) {
Identifier bodyName =
Impl.importFullName(param, Impl.CurrentVersion)
.getBaseIdentifier(Impl.SwiftContext);
auto paramInfo = Impl.createDeclWithClangNode<ParamDecl>(
param, AccessLevel::Private, SourceLoc(), SourceLoc(),
Identifier(), Impl.importSourceLoc(param->getLocation()),
bodyName, Impl.ImportedHeaderUnit);
paramInfo->setSpecifier(ParamSpecifier::Default);
paramInfo->setInterfaceType(Impl.SwiftContext.TheAnyType);
if (param->hasDefaultArg()) {
paramInfo->setDefaultArgumentKind(DefaultArgumentKind::Normal);
paramInfo->setDefaultValueStringRepresentation("cxxDefaultArg");
}
params.push_back(paramInfo);
}
bodyParams = ParameterList::create(Impl.SwiftContext, params);
}
} else {
// Import the function type. If we have parameters, make sure their
// names get into the resulting function type.
importedType = Impl.importFunctionParamsAndReturnType(
dc, decl, {decl->param_begin(), decl->param_size()},
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
templateParams);
}
// Import the function type. If we have parameters, make sure their
// names get into the resulting function type.
importedType = Impl.importFunctionParamsAndReturnType(
dc, decl, {decl->param_begin(), decl->param_size()},
decl->isVariadic(), isInSystemModule(dc), name, bodyParams,
templateParams);
if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
if (mdecl->isStatic()) {
@@ -4160,12 +4121,10 @@ namespace {
}
func->setAccess(importer::convertClangAccess(decl->getAccess()));
if (!importFuncWithoutSignature) {
bool success = processSpecialImportedFunc(
func, importedName, decl->getOverloadedOperator());
if (!success)
return nullptr;
}
bool success = processSpecialImportedFunc(
func, importedName, decl->getOverloadedOperator());
if (!success)
return nullptr;
}
result->setIsObjC(false);
@@ -4480,8 +4439,7 @@ namespace {
}
Decl *VisitFieldDecl(const clang::FieldDecl *decl) {
if (!Impl.importSymbolicCXXDecls &&
decl->hasAttr<clang::NoUniqueAddressAttr>()) {
if (decl->hasAttr<clang::NoUniqueAddressAttr>()) {
if (const auto *rd = decl->getType()->getAsRecordDecl()) {
// Clang can store the next field in the padding of this one. Swift
// does not support this yet so let's not import the field and
@@ -4743,11 +4701,6 @@ namespace {
if (name.empty())
return nullptr;
if (Impl.importSymbolicCXXDecls)
// Import an unspecialized C++ class template as a Swift value/class
// type in symbolic mode.
return Impl.importDecl(decl->getTemplatedDecl(), Impl.CurrentVersion);
auto loc = Impl.importSourceLoc(decl->getLocation());
auto dc = Impl.importDeclContextOf(
decl, importedName.getEffectiveContext());

View File

@@ -2274,11 +2274,6 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
if (auto classTemplateSpecDecl =
dyn_cast<clang::ClassTemplateSpecializationDecl>(D)) {
/// Symbolic specializations get imported as the symbolic class template
/// type.
if (importSymbolicCXXDecls)
return importNameImpl(classTemplateSpecDecl->getSpecializedTemplate(),
version, givenName);
if (!isa<clang::ClassTemplatePartialSpecializationDecl>(D)) {
auto name = printClassTemplateSpecializationName(classTemplateSpecDecl,
swiftCtx, this, version);

View File

@@ -423,8 +423,6 @@ class NameImporter {
llvm::DenseMap<std::pair<const clang::ObjCInterfaceDecl *, char>,
std::unique_ptr<InheritedNameSet>> allProperties;
bool importSymbolicCXXDecls;
ClangImporter::Implementation *importerImpl;
public:
@@ -432,8 +430,6 @@ public:
clang::Sema &cSema, ClangImporter::Implementation *importerImpl)
: swiftCtx(ctx), availability(avail), clangSema(cSema),
enumInfos(clangSema.getPreprocessor()),
importSymbolicCXXDecls(
ctx.LangOpts.hasFeature(Feature::ImportSymbolicCXXDecls)),
importerImpl(importerImpl) {}
/// Determine the Swift name for a Clang decl
@@ -498,10 +494,6 @@ public:
clang::ObjCInterfaceDecl *classDecl,
bool forInstance);
inline void enableSymbolicImportFeature(bool isEnabled) {
importSymbolicCXXDecls = isEnabled;
}
/// Retrieve a purported custom name even if it is invalid.
static std::optional<StringRef>
findCustomName(const clang::Decl *decl, ImportNameVersion version);

View File

@@ -75,10 +75,6 @@ bool ClangImporter::Implementation::isOverAligned(const clang::TypeDecl *decl) {
}
bool ClangImporter::Implementation::isOverAligned(clang::QualType type) {
// Do not check type layout for a clang type in symbolic mode as the
// type could be a dependent type.
if (importSymbolicCXXDecls)
return false;
auto align = getClangASTContext().getTypeAlignInChars(type);
return align > clang::CharUnits::fromQuantity(MaximumAlignment);
}
@@ -2348,10 +2344,6 @@ findGenericTypeInGenericDecls(ClangImporter::Implementation &impl,
llvm::find_if(genericParams, [name](GenericTypeParamDecl *generic) {
return generic->getName().str() == name;
});
// We sometimes are unable compute the exact Swift type
// of symbolic declarations. Fallback to using `Any` in that case.
if (impl.importSymbolicCXXDecls && genericParamIter == genericParams.end())
return impl.SwiftContext.TheAnyType;
// TODO: once we support generics in class types, replace this with
// "return nullptr". Once support for template classes, this will need to
// be updated, though. I'm leaving the assert here to make it easier to

View File

@@ -475,7 +475,6 @@ public:
const bool DisableOverlayModules;
const bool EnableClangSPI;
const bool UseClangIncludeTree;
bool importSymbolicCXXDecls;
bool IsReadingBridgingPCH;
llvm::SmallVector<clang::serialization::SubmoduleID, 2> PCHImportedSubmodules;

View File

@@ -2020,11 +2020,6 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod(
assert(!method->isStatic() ||
method->getNameInfo().getName().getCXXOverloadedOperator() ==
clang::OO_Call);
// When emitting symbolic decls, the method might not have a concrete
// record type as this type.
if (ImporterImpl.importSymbolicCXXDecls && !method->isStatic() &&
!method->getThisType()->getPointeeCXXRecordDecl())
return nullptr;
// Create a new method in the derived class that calls the base method.
clang::DeclarationName name = method->getNameInfo().getName();

View File

@@ -836,27 +836,3 @@ void swift::ide::printHeaderInterface(
}
Printer.forceNewlines();
}
void swift::ide::printSymbolicSwiftClangModuleInterface(
ModuleDecl *M, ASTPrinter &Printer, const clang::Module *clangModule) {
std::string headerComment;
llvm::raw_string_ostream(headerComment)
<< "// Swift interface for " << (clangModule->IsSystem ? "system " : "")
<< "module '" << clangModule->Name << "'\n";
Printer.printText(headerComment);
ModuleTraversalOptions opts;
opts |= ModuleTraversal::VisitSubmodules;
auto popts =
PrintOptions::printModuleInterface(/*printFullConvention=*/false);
popts.PrintDocumentationComments = false;
popts.SkipInlineCXXNamespace = true;
auto &SwiftContext = M->getTopLevelModule()->getASTContext();
auto &Importer =
static_cast<ClangImporter &>(*SwiftContext.getClangModuleLoader());
Importer.withSymbolicFeatureEnabled([&]() {
printModuleInterface(M, {}, opts, Printer, popts,
/*SynthesizeExtensions=*/false);
});
}

View File

@@ -426,199 +426,6 @@ emitDataForSwiftSerializedModule(ModuleDecl *module,
const PathRemapper &pathRemapper,
SourceFile *initialFile);
static void
appendSymbolicInterfaceToIndexStorePath(SmallVectorImpl<char> &resultingPath) {
llvm::sys::path::append(resultingPath, "interfaces");
}
static llvm::Error initSymbolicInterfaceStorePath(StringRef storePath) {
SmallString<128> subPath = storePath;
appendSymbolicInterfaceToIndexStorePath(subPath);
std::error_code ec = llvm::sys::fs::create_directories(subPath);
if (ec)
return llvm::errorCodeToError(ec);
return llvm::Error::success();
}
static void appendSymbolicInterfaceClangModuleFilename(
StringRef filePath, SmallVectorImpl<char> &resultingPath) {
llvm::sys::path::append(resultingPath, llvm::sys::path::filename(filePath));
StringRef extension = ".symbolicswiftinterface";
resultingPath.append(extension.begin(), extension.end());
}
// FIXME (Alex): Share code with IndexUnitWriter in LLVM after refactoring it.
static llvm::Expected<bool>
isFileUpToDateForOutputFile(StringRef filePath, StringRef timeCompareFilePath) {
auto makeError = [](StringRef path, std::error_code ec) -> llvm::Error {
std::string error;
llvm::raw_string_ostream(error)
<< "could not access path '" << path << "': " << ec.message();
return llvm::createStringError(ec, error.c_str());
};
llvm::sys::fs::file_status unitStat;
if (std::error_code ec = llvm::sys::fs::status(filePath, unitStat)) {
if (ec != std::errc::no_such_file_or_directory && ec != llvm::errc::delete_pending)
return makeError(filePath, ec);
return false;
}
if (timeCompareFilePath.empty())
return true;
llvm::sys::fs::file_status compareStat;
if (std::error_code ec =
llvm::sys::fs::status(timeCompareFilePath, compareStat)) {
if (ec != std::errc::no_such_file_or_directory && ec != llvm::errc::delete_pending)
return makeError(timeCompareFilePath, ec);
return true;
}
// Return true (unit is up-to-date) if the file to compare is older than the
// unit file.
return compareStat.getLastModificationTime() <=
unitStat.getLastModificationTime();
}
/// Emit the symbolic swift interface file for an imported Clang module into the
/// index store directory.
///
/// The swift interface file is emitted only when it doesn't exist yet, or when
/// the PCM for the Clang module has been updated.
///
/// System modules without the 'cplusplus' requirement are not emitted.
static void emitSymbolicInterfaceForClangModule(
ClangModuleUnit *clangModUnit, ModuleDecl *M,
const clang::Module *clangModule, StringRef indexStorePath,
const clang::CompilerInstance &clangCI, DiagnosticEngine &diags) {
if (!M->getASTContext().LangOpts.EnableCXXInterop)
return;
// Skip system modules without an explicit 'cplusplus' requirement.
bool isSystem = clangModUnit->isSystemModule();
if (isSystem && !importer::requiresCPlusPlus(clangModule))
return;
// Make sure the `interfaces` directory is created.
if (auto err = initSymbolicInterfaceStorePath(indexStorePath)) {
llvm::handleAllErrors(std::move(err), [&](const llvm::ECError &ec) {
diags.diagnose(SourceLoc(), diag::error_create_symbolic_interfaces_dir,
ec.convertToErrorCode().message());
});
return;
}
auto moduleRef = clangModule->getASTFile();
if (!moduleRef)
return;
// Determine the output name for the symbolic interface file.
clang::serialization::ModuleFile *ModFile =
clangCI.getASTReader()->getModuleManager().lookup(*moduleRef);
assert(ModFile && "no module file loaded for module ?");
SmallString<128> interfaceOutputPath = indexStorePath;
appendSymbolicInterfaceToIndexStorePath(interfaceOutputPath);
appendSymbolicInterfaceClangModuleFilename(ModFile->FileName,
interfaceOutputPath);
// Check if the symbolic interface file is already up to date.
std::string error;
auto upToDate =
isFileUpToDateForOutputFile(interfaceOutputPath, ModFile->FileName);
if (!upToDate) {
llvm::handleAllErrors(
upToDate.takeError(), [&](const llvm::StringError &ec) {
diags.diagnose(SourceLoc(),
diag::error_symbolic_interfaces_failed_status_check,
ec.getMessage());
});
return;
}
if (M->getASTContext().LangOpts.EnableIndexingSystemModuleRemarks) {
diags.diagnose(SourceLoc(), diag::remark_emitting_symbolic_interface_module,
interfaceOutputPath, *upToDate);
}
if (*upToDate)
return;
// Output the interface to a temporary file first.
SmallString<128> tempOutputPath = interfaceOutputPath;
tempOutputPath += "-%%%%%%%%";
int tempFD;
if (llvm::sys::fs::createUniqueFile(tempOutputPath.str(), tempFD,
tempOutputPath)) {
llvm::raw_string_ostream errOS(error);
errOS << "failed to create temporary file: " << tempOutputPath;
diags.diagnose(SourceLoc(), diag::error_write_symbolic_interface,
errOS.str());
return;
}
llvm::raw_fd_ostream os(tempFD, /*shouldClose=*/true);
StreamPrinter printer(os);
ide::printSymbolicSwiftClangModuleInterface(M, printer, clangModule);
os.close();
if (os.has_error()) {
llvm::raw_string_ostream errOS(error);
errOS << "failed to write '" << tempOutputPath
<< "': " << os.error().message();
diags.diagnose(SourceLoc(), diag::error_write_symbolic_interface,
errOS.str());
os.clear_error();
llvm::sys::fs::remove(tempOutputPath);
return;
}
// Move the resulting output to the destination symbolic interface file.
std::error_code ec = llvm::sys::fs::rename(
/*from=*/tempOutputPath, /*to=*/interfaceOutputPath);
if (ec) {
llvm::raw_string_ostream errOS(error);
errOS << "failed to rename '" << tempOutputPath << "' to '"
<< interfaceOutputPath << "': " << ec.message();
diags.diagnose(SourceLoc(), diag::error_write_symbolic_interface,
errOS.str());
llvm::sys::fs::remove(tempOutputPath);
return;
}
}
static void emitTransitiveClangSymbolicInterfacesForSwiftModuleImports(
ArrayRef<ImportedModule> imports, StringRef indexStorePath,
const clang::CompilerInstance &clangCI, DiagnosticEngine &diags) {
auto &fileMgr = clangCI.getFileManager();
for (auto &import : imports) {
ModuleDecl *mod = import.importedModule;
if (mod->isOnoneSupportModule())
continue; // ignore the Onone support library.
if (mod->isSwiftShimsModule())
continue;
for (auto *FU : mod->getFiles()) {
switch (FU->getKind()) {
default:
break;
case FileUnitKind::SerializedAST:
case FileUnitKind::DWARFModule:
case FileUnitKind::ClangModule: {
auto *LFU = cast<LoadedFile>(FU);
if (auto F = fileMgr.getFile(LFU->getFilename())) {
if (FU->getKind() == FileUnitKind::ClangModule) {
auto clangModUnit = cast<ClangModuleUnit>(LFU);
if (auto clangMod = clangModUnit->getUnderlyingClangModule()) {
// Emit the symbolic interface file in addition to index data.
emitSymbolicInterfaceForClangModule(
clangModUnit, mod, clangMod, indexStorePath, clangCI, diags);
}
}
// FIXME: We should keep recursing here into other Swift modules.
}
}
}
}
}
}
static void addModuleDependencies(ArrayRef<ImportedModule> imports,
StringRef indexStorePath,
bool indexClangModules,
@@ -688,11 +495,6 @@ static void addModuleDependencies(ArrayRef<ImportedModule> imports,
if (shouldIndexModule)
clang::index::emitIndexDataForModuleFile(clangMod,
clangCI, unitWriter);
// Emit the symbolic interface file in addition to index data.
if (indexClangModules)
emitSymbolicInterfaceForClangModule(clangModUnit, mod, clangMod,
indexStorePath, clangCI,
diags);
}
} else {
// Serialized AST file.
@@ -727,9 +529,6 @@ static void addModuleDependencies(ArrayRef<ImportedModule> imports,
SmallVector<ImportedModule, 4> imports;
mod->getImportedModules(imports,
ModuleDecl::ImportFilterKind::Exported);
if (indexClangModules)
emitTransitiveClangSymbolicInterfacesForSwiftModuleImports(
imports, indexStorePath, clangCI, diags);
}
}
clang::index::writer::OpaqueModule opaqMod =

View File

@@ -1,30 +0,0 @@
// Only run this test with older libc++, before the top-level std module got split into multiple top-level modules.
// RUN: %empty-directory(%t)
// RUN: %target-clangxx %S/Inputs/check-libcxx-version.cpp -o %t/check-libcxx-version
// RUN: %target-codesign %t/check-libcxx-version
// RUN: %target-swift-ide-test -print-module -module-to-print=CxxStdlib -source-filename=x -enable-experimental-cxx-interop -enable-objc-interop -module-print-submodules -enable-experimental-feature ImportSymbolicCXXDecls > %t/result.txt
// RUN: %target-run %t/check-libcxx-version || %FileCheck %s --check-prefixes=CHECK,VECTOR --input-file=%t/result.txt
// RUN: %target-run %t/check-libcxx-version || %FileCheck %s --check-prefixes=CHECK,STRING --input-file=%t/result.txt
// RUN: %target-run %t/check-libcxx-version || %FileCheck %s --check-prefixes=CHECK,MAP --input-file=%t/result.txt
// REQUIRES: OS=macosx
// REQUIRES: swift_feature_ImportSymbolicCXXDecls
// Since this test runs check-libcxx-version, it requires execution.
// REQUIRES: executable_test
// CHECK: enum std {
// CHECK: enum __1 {
// STRING: struct basic_string {
// STRING: typealias string = std.__1.basic_string
// VECTOR: struct vector {
// VECTOR: mutating func push_back(_ __x: Any)
// VECTOR: }
// MAP: struct map {
// CHECK-NOT: enum std

View File

@@ -1,16 +0,0 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: %target-swift-frontend %t/test.swift -I %t -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// REQUIRES: OS=macosx
// REQUIRES: cxx-interop-fixed-cf_options
//--- test.swift
import CxxStdlib
import Foundation
// FILES: std-{{.*}}.pcm.symbolicswiftinterface
// FILES-NOT: Foundation*

View File

@@ -1,45 +0,0 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// Verify that symbolic interfaces are emitted.
//
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>%t/remarks
// RUN: echo "EOF" >> %t/remarks
// RUN: cat %t/remarks | %FileCheck --check-prefix=REMARK_NEW %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// RUN: cat %t/store/interfaces/std* | %FileCheck --check-prefix=CHECK %s
// Verify that symbolic interfaces are not emitted when PCM doesn't change.
//
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>&1 | %FileCheck --check-prefix=REMARK_NO_UPDATE %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// REQUIRES: OS=macosx
//--- Inputs/module.modulemap
module CxxModule {
header "headerA.h"
requires cplusplus
}
//--- Inputs/headerA.h
int freeFunction(int x, int y);
//--- test.swift
import CxxStdlib
import CxxModule
// CHECK-NOT: warning: 'import_owned' Swift attribute ignored on type
// REMARK_NEW: remark: emitting symbolic interface at {{.*}}/interfaces/std-{{.*}}.pcm.symbolicswiftinterface{{$}}
// REMARK_NEW: remark: emitting symbolic interface at {{.*}}/interfaces/CxxModule-{{.*}}.pcm.symbolicswiftinterface{{$}}
// REMARK_NO_UPDATE-NOT: remark: emitting symbolic interface at {{.*}}/interfaces/std-{{.*}}.pcm.symbolicswiftinterface{{$}}
// REMARK_NO_UPDATE-NOT: remark: emitting symbolic interface at {{.*}}/interfaces/CxxModule-{{.*}}.pcm.symbolicswiftinterface{{$}}
// FILES: CxxModule-{{.*}}.pcm.symbolicswiftinterface
// FILES: std-{{.*}}.pcm.symbolicswiftinterface
// CHECK: // Swift interface for system module 'std'

View File

@@ -1,23 +0,0 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
//
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-ignore-clang-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>&1 | %FileCheck %s
// RUN: not ls %t/store/interfaces
//--- Inputs/module.modulemap
module CxxModule {
header "headerA.h"
requires cplusplus
}
//--- Inputs/headerA.h
namespace ns {
int freeFunction(int x, int y);
}
//--- test.swift
import CxxModule
// CHECK-NOT: emitting symbolic interface at

View File

@@ -1,62 +0,0 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>&1 | %FileCheck --check-prefix=REMARK_NEW %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// RUN: cat %t/store/interfaces/ObjCxxModule* | %FileCheck --check-prefix=CHECK %s
// Verify that symbolic interface is not emitted without interop.
//
// RUN: rm -r %t/store/interfaces
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -Rindexing-system-module 2>&1 > %t/out
// RUN: echo "non-empty-file-check" >> %t/out
// RUN: cat %t/out | %FileCheck --check-prefix=REMARK_NONE %s
// RUN: not ls %t/store/interfaces
// REQUIRES: objc_interop
// REQUIRES: cxx-interop-fixed-cf_options
//--- Inputs/module.modulemap
module ObjCxxModule {
header "headerA.h"
// NOTE: does not require cplusplus
}
//--- Inputs/headerA.h
#include <Foundation/Foundation.h>
#ifdef __cplusplus
namespace ns {
int freeCxxFunction(int x, int y);
}
#endif
@interface ObjCClass: NSObject
- (void)myTestMethod;
@end
//--- test.swift
import ObjCxxModule
// REMARK_NEW: remark: emitting symbolic interface at {{.*}}/interfaces/ObjCxxModule-{{.*}}.pcm.symbolicswiftinterface{{$}}
// REMARK_NONE-NOT: emitting symbolic interface at
// FILES: ObjCxxModule-{{.*}}.pcm.symbolicswiftinterface
// CHECK: // Swift interface for module 'ObjCxxModule'
// CHECK-NEXT: import Foundation
// CHECK-EMPTY:
// CHECK-NEXT: public enum ns {
// CHECK-EMPTY:
// CHECK-NEXT: public static func freeCxxFunction(_ x: Int32, _ y: Int32) -> Int32
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: open class ObjCClass : NSObject {
// CHECK-EMPTY:
// CHECK-NEXT: open func myTestMethod()
// CHECK-NEXT: }

View File

@@ -1,45 +0,0 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop 2>&1
// RUN: cat %t/store/interfaces/CxxModule* | %FileCheck --check-prefix=CHECK %s
//--- Inputs/module.modulemap
module CxxModule {
header "header.h"
requires cplusplus
}
//--- Inputs/header.h
namespace ns {
template<class T>
struct TemplateRecord {
void methodFunc(int x) const;
};
}
using TemplateRecordInt = ns::TemplateRecord<int>;
//--- test.swift
import CxxModule
public func useConcreteTemplate() {
let x = TemplateRecordInt()
x.methodFunc(2)
}
// CHECK: // Swift interface for module 'CxxModule'
// CHECK: public enum ns {
// CHECK-EMPTY:
// CHECK-NEXT: public struct TemplateRecord {
// CHECK-EMPTY:
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: public init()
// CHECK-EMPTY:
// CHECK-NEXT: public func methodFunc(_ x: Any)
// CHECK-NEXT:}
// CHECK-NEXT:}
// CHECK-EMPTY:
// CHECK-NEXT: public typealias TemplateRecordInt = ns.TemplateRecord

View File

@@ -1,164 +0,0 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// Verify that symbolic interfaces are emitted.
//
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>%t/remarks
// RUN: echo "EOF" >> %t/remarks
// RUN: cat %t/remarks | %FileCheck --check-prefixes=REMARK_NEW,REMARK_INITIAL %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// RUN: cat %t/store/interfaces/CxxModule* | %FileCheck --check-prefix=CHECK %s
// Verify that symbolic interfaces are not emitted when PCM doesn't change.
//
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>&1 | %FileCheck --check-prefix=REMARK_NO_UPDATE %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// RUN: cat %t/store/interfaces/CxxModule* | %FileCheck --check-prefix=CHECK %s
// Verify that symbolic interface is re-emitted when the interface is removed.
//
// RUN: rm -r %t/store/interfaces
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>&1 | %FileCheck --check-prefix=REMARK_NEW %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// RUN: cat %t/store/interfaces/CxxModule* | %FileCheck --check-prefixes=CHECK %s
// Verify that symbolic interface is re-emitted when PCM changes.
//
// RUN: echo "using AdditionalAlias = int;" >> %t/Inputs/headerA.h
// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -c -index-system-modules -index-store-path %t/store -enable-experimental-cxx-interop -Rindexing-system-module 2>&1 | %FileCheck --check-prefix=REMARK_NEW %s
// RUN: ls %t/store/interfaces | %FileCheck --check-prefix=FILES %s
// RUN: cat %t/store/interfaces/CxxModule* | %FileCheck --check-prefixes=CHECK,CHECK-UPDATED %s
//--- Inputs/module.modulemap
module CxxModule {
header "headerA.h"
header "headerB.h"
requires cplusplus
}
module TransitiveCppMod {
header "transitiveHeader.h"
requires cplusplus
}
//--- Inputs/headerA.h
namespace ns {
int freeFunction(int x, int y);
}
//--- Inputs/transitiveHeader.h
template<class T>
struct TransitiveStruct {
T x;
void test() {}
};
//--- Inputs/headerB.h
#include "headerA.h"
#include "transitiveHeader.h"
namespace ns {
struct B {
int y;
};
template<class T>
struct TemplateRecord {
void methodFunc(int x);
struct InnerRecord {
int innerMethod(int y);
};
template<class T2>
struct InnerTemplate {
void innerTemplateMethod();
};
InnerTemplate<int> returnsTemplateMethod();
};
inline namespace __1 {
struct StructInInlineNamespace {
};
using TypealiasInInlineNamespace = TemplateRecord<StructInInlineNamespace>;
}
using TypealiasOfInlineNamespace = __1::StructInInlineNamespace;
}
using MyType = ns::TemplateRecord<int>;
using MyType2 = TransitiveStruct<int>;
//--- test.swift
import CxxModule
// REMARK_INITIAL: remark: emitting symbolic interface at {{.*}}{{/|\\}}interfaces{{/|\\}}CxxShim-{{.*}}.pcm.symbolicswiftinterface{{$}}
// REMARK_NEW: remark: emitting symbolic interface at {{.*}}{{/|\\}}interfaces{{/|\\}}CxxModule-{{.*}}.pcm.symbolicswiftinterface{{$}}
// REMARK_INITIAL-NEXT: EOF
// REMARK_NO_UPDATE: remark: emitting symbolic interface at {{.*}}{{/|\\}}interfaces{{/|\\}}CxxModule-{{.*}}.pcm.symbolicswiftinterface; skipping because it's up to date{{$}}
// FILES: CxxModule-{{.*}}.pcm.symbolicswiftinterface
// FILES-NOT: TransitiveCppMod
// CHECK: // Swift interface for module 'CxxModule'
// CHECK-UPDATED: typealias AdditionalAlias =
// CHECK: enum ns {
// CHECK-EMPTY:
// CHECK-NEXT: struct B {
// CHECK-EMPTY:
// CHECK-NEXT: init()
// CHECK-EMPTY:
// CHECK-NEXT: init(y: Int32)
// CHECK-EMPTY:
// CHECK-NEXT: var y: Int32
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: struct TemplateRecord {
// CHECK-EMPTY:
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: public init()
// CHECK-EMPTY:
// CHECK-NEXT: mutating func methodFunc(_ x: Any)
// CHECK-EMPTY:
// CHECK-NEXT: struct InnerRecord {
// CHECK-EMPTY:
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: public init()
// CHECK-EMPTY:
// CHECK-NEXT: mutating func innerMethod(_ y: Any)
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: struct InnerTemplate {
// CHECK-EMPTY:
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: public init()
// CHECK-EMPTY:
// CHECK-NEXT: mutating func innerTemplateMethod()
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: mutating func returnsTemplateMethod()
// CHECK-NEXT: }
// CHECK: public struct StructInInlineNamespace {
// CHECK-EMPTY:
// CHECK-NEXT: public init()
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: public typealias TypealiasInInlineNamespace = ns.TemplateRecord
// CHECK-EMPTY:
// CHECK-EMPTY:
// CHECK-NEXT: public typealias TypealiasOfInlineNamespace = ns.StructInInlineNamespace
// CHECK-EMPTY:
// CHECK-NEXT: static func freeFunction(_ x: Int32, _ y: Int32) -> Int32
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: typealias MyType = ns.TemplateRecord
// CHECK-EMPTY:
// CHECK-NEXT: typealias MyType2 = TransitiveStruct

View File

@@ -1,128 +0,0 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: %target-swift-ide-test -print-module -module-to-print=CxxModule -I %t/Inputs -source-filename=x -enable-experimental-cxx-interop -enable-experimental-feature ImportSymbolicCXXDecls 2>&1 | %FileCheck %s
// REQUIRES: swift_feature_ImportSymbolicCXXDecls
//--- Inputs/module.modulemap
module CxxModule {
header "headerA.h"
header "headerB.h"
requires cplusplus
}
//--- Inputs/headerA.h
namespace ns {
int freeFunction(int x, int y);
}
//--- Inputs/headerB.h
#include "headerA.h"
namespace ns {
struct B {
int y;
};
template<class T>
struct TemplateRecord {
void methodFunc(int x);
struct InnerRecord {
int innerMethod(int y);
};
template<class T2>
struct InnerTemplate {
void innerTemplateMethod();
void innerTemplateMethodWithDefaultArg(T2 x = 123);
};
InnerTemplate<int> returnsTemplateMethod();
};
}
using MyType = ns::TemplateRecord<int>;
template<class X>
class OuterTemp2 {
public:
template<class T, class G>
class InnerTemp2 {
public:
void testMe(const T& p, const X& x);
X x2;
using Y = X;
};
};
template <class T>
struct __attribute__((swift_attr("import_owned"))) AnnotatedTemplate {
T t;
};
#define IMMORTAL_FRT \
__attribute__((swift_attr("import_reference"))) \
__attribute__((swift_attr("retain:immortal"))) \
__attribute__((swift_attr("release:immortal")))
struct IMMORTAL_FRT MyImmortal {
virtual void foo() const {};
};
struct NonCopyable {
NonCopyable(const NonCopyable& other) = delete;
};
// CHECK-NOT: warning: 'import_owned' Swift attribute ignored on type
// CHECK: enum ns {
// CHECK-NEXT: struct B {
// CHECK-NEXT: init()
// CHECK-NEXT: init(y: Int32)
// CHECK-NEXT: var y: Int32
// CHECK-NEXT: }
// CHECK-NEXT: struct TemplateRecord {
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: init()
// CHECK-NEXT: mutating func methodFunc(_ x: Any)
// CHECK-NEXT: struct InnerRecord {
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: init()
// CHECK-NEXT: mutating func innerMethod(_ y: Any)
// CHECK-NEXT: }
// CHECK-NEXT: struct InnerTemplate {
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: init()
// CHECK-NEXT: mutating func innerTemplateMethod()
// CHECK-NEXT: mutating func innerTemplateMethodWithDefaultArg(_ x: Any = cxxDefaultArg)
// CHECK-NEXT: }
// CHECK-NEXT: mutating func returnsTemplateMethod()
// CHECK-NEXT: }
// CHECK-NEXT: static func freeFunction(_ x: Int32, _ y: Int32) -> Int32
// CHECK-NEXT: }
// CHECK-NEXT: typealias MyType = ns.TemplateRecord
// CHECK-NEXT: struct OuterTemp2 {
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: init()
// CHECK-NEXT: struct InnerTemp2 {
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: init()
// CHECK-NEXT: init(x2: Any)
// CHECK-NEXT: mutating func testMe(_ p: Any, _ x: Any)
// CHECK-NEXT: var x2: Any
// CHECK-NEXT: typealias Y = Any
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK: class MyImmortal {
// CHECK-NEXT: init
// CHECK-NEXT: func foo()
// CHECK-NEXT: }
// CHECK-NEXT: struct NonCopyable {
// CHECK-NEXT: @available(*, deprecated, message:
// CHECK-NEXT: init()
// CHECK-NEXT: }