diff --git a/include/clang/APINotes/APINotesManager.h b/include/clang/APINotes/APINotesManager.h index 69752a9c77e..7f540b9c17d 100644 --- a/include/clang/APINotes/APINotesManager.h +++ b/include/clang/APINotes/APINotesManager.h @@ -111,6 +111,10 @@ class APINotesManager { /// Find the API notes reader that corresponds to the given source location. APINotesReader *findAPINotes(SourceLocation Loc); + + APINotesReader *getCurrentModuleReader() { + return CurrentModuleReader.get(); + } }; } // end namespace api_notes diff --git a/include/clang/APINotes/APINotesReader.h b/include/clang/APINotes/APINotesReader.h index 839e1dc5ee9..29dcc1f56f9 100644 --- a/include/clang/APINotes/APINotesReader.h +++ b/include/clang/APINotes/APINotesReader.h @@ -50,6 +50,9 @@ class APINotesReader { /// notes. StringRef getModuleName() const; + /// Retrieve the module options + ModuleOptions getModuleOptions() const; + /// Look for information regarding the given Objective-C class. /// /// \param name The name of the class we're looking for. diff --git a/include/clang/APINotes/APINotesWriter.h b/include/clang/APINotes/APINotesWriter.h index 66dc8ffebba..aa41756b2e7 100644 --- a/include/clang/APINotes/APINotesWriter.h +++ b/include/clang/APINotes/APINotesWriter.h @@ -107,6 +107,9 @@ class APINotesWriter { /// \param name The name of this typedef. /// \param info Information about this typedef. void addTypedef(StringRef name, const TypedefInfo &info); + + /// Add module options + void addModuleOptions(ModuleOptions opts); }; } // end namespace api_notes diff --git a/include/clang/APINotes/Types.h b/include/clang/APINotes/Types.h index 2fc4ee8fe73..7b4d0647ef2 100644 --- a/include/clang/APINotes/Types.h +++ b/include/clang/APINotes/Types.h @@ -474,6 +474,11 @@ class TypedefInfo : public CommonTypeInfo { TypedefInfo() : CommonTypeInfo() { } }; +/// Descripts a series of options for a module +struct ModuleOptions { + bool SwiftInferImportAsMember; +}; + } // end namespace api_notes } // end namespace clang diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index c95968d9a75..f8bdf0618fe 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -183,6 +183,9 @@ class Module { /// \brief Whether this is an inferred submodule (module * { ... }). unsigned IsInferred : 1; + /// \brief Whether this is a module who has its swift_names inferred. + unsigned IsSwiftInferImportAsMember : 1; + /// \brief Whether we should infer submodules for this module based on /// the headers. /// diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 6d171b24f24..4d96644beae 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -176,6 +176,9 @@ class ModuleMap { /// \brief Whether this is an exhaustive set of configuration macros. unsigned IsExhaustive : 1; + + /// \brief Whether this is a module who has its swift_names inferred. + unsigned IsSwiftInferImportAsMember : 1; }; /// \brief A directory for which framework modules can be inferred. diff --git a/lib/APINotes/APINotesFormat.h b/lib/APINotes/APINotesFormat.h index d344a30a661..0e8ca3368f6 100644 --- a/lib/APINotes/APINotesFormat.h +++ b/lib/APINotes/APINotesFormat.h @@ -35,7 +35,7 @@ const uint16_t VERSION_MAJOR = 0; /// API notes file minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t VERSION_MINOR = 10; // enum constants +const uint16_t VERSION_MINOR = 11; // SwiftInferImportAsMember using IdentifierID = Fixnum<31>; using IdentifierIDField = BCVBR<16>; @@ -104,7 +104,8 @@ namespace control_block { // VERSION_MAJOR. enum { METADATA = 1, - MODULE_NAME = 2 + MODULE_NAME = 2, + MODULE_OPTIONS = 3 }; using MetadataLayout = BCRecordLayout< @@ -117,6 +118,11 @@ namespace control_block { MODULE_NAME, BCBlob // Module name >; + + using ModuleOptionsLayout = BCRecordLayout< + MODULE_OPTIONS, + BCFixed<1> // SwiftInferImportAsMember + >; } namespace identifier_block { diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp index 62acecf3cc8..d424b39e3aa 100644 --- a/lib/APINotes/APINotesReader.cpp +++ b/lib/APINotes/APINotesReader.cpp @@ -562,6 +562,9 @@ class APINotesReader::Implementation { /// The name of the module that we read from the control block. std::string ModuleName; + /// Various options and attributes for the module + ModuleOptions ModuleOpts; + using SerializedIdentifierTable = llvm::OnDiskIterableChainedHashTable; @@ -735,6 +738,10 @@ bool APINotesReader::Implementation::readControlBlock( ModuleName = blobData.str(); break; + case control_block::MODULE_OPTIONS: + ModuleOpts.SwiftInferImportAsMember = (scratch.front() & 1) != 0; + break; + default: // Unknown metadata record, possibly for use by a future version of the // module format. @@ -1440,6 +1447,10 @@ StringRef APINotesReader::getModuleName() const { return Impl.ModuleName; } +ModuleOptions APINotesReader::getModuleOptions() const { + return Impl.ModuleOpts; +} + auto APINotesReader::lookupObjCClass(StringRef name) -> Optional> { if (!Impl.ObjCContextTable) diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp index 80c1f3487b3..425186ec2f7 100644 --- a/lib/APINotes/APINotesWriter.cpp +++ b/lib/APINotes/APINotesWriter.cpp @@ -43,6 +43,8 @@ class APINotesWriter::Implementation { /// The name of the module std::string ModuleName; + bool SwiftInferImportAsMember = false; + /// Information about Objective-C contexts (classes or protocols). /// /// Indexed by the identifier ID and a bit indication whether we're looking @@ -214,6 +216,11 @@ void APINotesWriter::Implementation::writeControlBlock( control_block::ModuleNameLayout moduleName(writer); moduleName.emit(ScratchRecord, ModuleName); + + if (SwiftInferImportAsMember) { + control_block::ModuleOptionsLayout moduleOptions(writer); + moduleOptions.emit(ScratchRecord, SwiftInferImportAsMember); + } } namespace { @@ -1091,3 +1098,8 @@ void APINotesWriter::addTypedef(llvm::StringRef name, const TypedefInfo &info) { assert(!Impl.Typedefs.count(typedefID)); Impl.Typedefs[typedefID] = info; } + +void APINotesWriter::addModuleOptions(ModuleOptions opts) { + Impl.SwiftInferImportAsMember = opts.SwiftInferImportAsMember; +} + diff --git a/lib/APINotes/APINotesYAMLCompiler.cpp b/lib/APINotes/APINotesYAMLCompiler.cpp index 9ad6dd6a085..a9c21535c8e 100644 --- a/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/lib/APINotes/APINotesYAMLCompiler.cpp @@ -250,6 +250,8 @@ namespace { TagsSeq Tags; TypedefsSeq Typedefs; + llvm::Optional SwiftInferImportAsMember; + LLVM_ATTRIBUTE_DEPRECATED( void dump() LLVM_ATTRIBUTE_USED, "only for use within the debugger"); @@ -416,6 +418,7 @@ namespace llvm { io.mapRequired("Name", m.Name); io.mapOptional("Availability", m.Availability.Mode); io.mapOptional("AvailabilityMsg", m.Availability.Msg); + io.mapOptional("SwiftInferImportAsMember", m.SwiftInferImportAsMember); io.mapOptional("Classes", m.Classes); io.mapOptional("Protocols", m.Protocols); io.mapOptional("Functions", m.Functions); @@ -771,6 +774,9 @@ namespace { Writer->addTypedef(t.Name, typedefInfo); } + if (TheModule.SwiftInferImportAsMember) + Writer->addModuleOptions({true}); + if (!ErrorOccured) Writer->writeToStream(OS); @@ -1032,6 +1038,11 @@ bool api_notes::decompileAPINotes(std::unique_ptr input, // Set module name. module.Name = reader->getModuleName(); + // Set module options + auto opts = reader->getModuleOptions(); + if (opts.SwiftInferImportAsMember) + module.SwiftInferImportAsMember = true; + // Sort classes. std::sort(module.Classes.begin(), module.Classes.end(), [](const Class &lhs, const Class &rhs) -> bool { diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index b4f8d252d21..9e5b5807516 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -337,6 +337,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << " [system]"; if (IsExternC) OS << " [extern_c]"; + if (IsSwiftInferImportAsMember) + OS << " [swift_infer_import_as_member]"; } OS << " {\n"; diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index acb983af6a3..cdb9cf20a0b 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInstance.h" +#include "clang/APINotes/APINotesReader.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -533,10 +534,21 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind, TUKind, CompletionConsumer)); // If we're building a module, notify the API notes manager. - if (!getLangOpts().CurrentModule.empty()) { + StringRef currentModuleName = getLangOpts().CurrentModule; + if (!currentModuleName.empty()) { (void)TheSema->APINotes.loadCurrentModuleAPINotes( - getLangOpts().CurrentModule, + currentModuleName, getAPINotesOpts().ModuleSearchPaths); + // Check for any attributes we should add to the module + if (auto curReader = TheSema->APINotes.getCurrentModuleReader()) { + auto currentModule = getPreprocessor().getCurrentModule(); + assert(currentModule && "how can we have a reader for it?"); + + // swift_infer_import_as_member + if (curReader->getModuleOptions().SwiftInferImportAsMember) { + currentModule->IsSwiftInferImportAsMember = true; + } + } } } diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index ac766a97c9e..58aa6ee1902 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -1306,7 +1306,9 @@ namespace { /// \brief The 'extern_c' attribute. AT_extern_c, /// \brief The 'exhaustive' attribute. - AT_exhaustive + AT_exhaustive, + // \brief The 'swift_infer_import_as_member' attribute. + AT_swift_infer_import_as_member, }; } @@ -2379,6 +2381,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { .Case("exhaustive", AT_exhaustive) .Case("extern_c", AT_extern_c) .Case("system", AT_system) + .Case("swift_infer_import_as_member", AT_swift_infer_import_as_member) .Default(AT_unknown); switch (Attribute) { case AT_unknown: @@ -2394,6 +2397,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { Attrs.IsExternC = true; break; + case AT_swift_infer_import_as_member: + Attrs.IsSwiftInferImportAsMember = true; + break; + case AT_exhaustive: Attrs.IsExhaustive = true; break; diff --git a/test/APINotes/Inputs/Headers/APINotes.apinotes b/test/APINotes/Inputs/Headers/APINotes.apinotes index a4ddafe2892..08210fc7056 100644 --- a/test/APINotes/Inputs/Headers/APINotes.apinotes +++ b/test/APINotes/Inputs/Headers/APINotes.apinotes @@ -1,4 +1,5 @@ Name: HeaderLib +SwiftInferImportAsMember: true Functions: - Name: custom_realloc NullabilityOfRet: N diff --git a/test/APINotes/Inputs/roundtrip.apinotes b/test/APINotes/Inputs/roundtrip.apinotes index c34907ff67d..8509c79389b 100644 --- a/test/APINotes/Inputs/roundtrip.apinotes +++ b/test/APINotes/Inputs/roundtrip.apinotes @@ -2,6 +2,7 @@ Name: AppKit Availability: available AvailabilityMsg: '' +SwiftInferImportAsMember: true Classes: - Name: NSCell Availability: available diff --git a/test/Modules/Inputs/swift_name/module.modulemap b/test/Modules/Inputs/swift_name/module.modulemap new file mode 100644 index 00000000000..b7ec6b15988 --- /dev/null +++ b/test/Modules/Inputs/swift_name/module.modulemap @@ -0,0 +1,2 @@ +module SwiftNameInferred [swift_infer_import_as_member] { +} \ No newline at end of file diff --git a/test/Modules/infer_swift_name.m b/test/Modules/infer_swift_name.m new file mode 100644 index 00000000000..d4b4a5d4979 --- /dev/null +++ b/test/Modules/infer_swift_name.m @@ -0,0 +1,6 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/swift_name %s -verify +// REQUIRES: shell + +@import SwiftNameInferred; // ok +@import SwiftName; // expected-error{{module 'SwiftName' not found}}