mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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 ¶m : 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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
@@ -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*
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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: }
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: }
|
||||
Reference in New Issue
Block a user