def remark_module_build : Remark<"building module '%0' as '%1'">,
InGroup<DiagGroup<"module-build">>, DefaultIgnore;
+def err_conflicting_module_names : Error<
+ "conflicting module names specified: '-fmodule-name=%0' and "
+ "'-fmodule-implementation-of %1'">;
+
def err_missing_vfs_overlay_file : Error<
"virtual filesystem overlay file '%0' not found">, DefaultFatal;
def err_invalid_vfs_overlay : Error<
def note_module_import_not_at_top_level : Note<"%0 begins here">;
def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
+def err_module_import_in_implementation : Error<
+ "@import of module '%0' in implementation of '%1'; use #import">;
}
let CategoryName = "Documentation Issue" in {
/// \brief The name of the current module.
std::string CurrentModule;
+ /// \brief The name of the module that the translation unit is an
+ /// implementation of. Prevents semantic imports, but does not otherwise
+ /// treat this as the CurrentModule.
+ std::string ImplementationOfModule;
+
/// \brief Options for parsing comments.
CommentOptions CommentOpts;
HelpText<"Do not automatically generate or update the global module index">;
def fno_modules_error_recovery : Flag<["-"], "fno-modules-error-recovery">,
HelpText<"Do not automatically import modules for error recovery">;
+def fmodule_implementation_of : Separate<["-"], "fmodule-implementation-of">,
+ MetaVarName<"<name>">,
+ HelpText<"Specify the name of the module whose implementation file this is">;
let Group = Action_Group in {
Sanitize = SanitizerOptions::Disabled;
CurrentModule.clear();
+ ImplementationOfModule.clear();
}
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
// Make the named module visible.
- if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule)
+ if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule &&
+ ModuleName != getLangOpts().ImplementationOfModule)
ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
ImportLoc, /*Complain=*/false);
return LastModuleImportResult;
if (Known != KnownModules.end()) {
// Retrieve the cached top-level module.
Module = Known->second;
- } else if (ModuleName == getLangOpts().CurrentModule) {
+ } else if (ModuleName == getLangOpts().CurrentModule ||
+ ModuleName == getLangOpts().ImplementationOfModule) {
// This is the module we're building.
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
Module = Sub;
}
}
+
+ // Don't make the module visible if we are in the implementation.
+ if (ModuleName == getLangOpts().ImplementationOfModule)
+ return ModuleLoadResult(Module, false);
// Make the named module visible, if it's not already part of the module
// we are parsing.
Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+ Opts.ImplementationOfModule =
+ Args.getLastArgValue(OPT_fmodule_implementation_of);
+
+ if (!Opts.CurrentModule.empty() && !Opts.ImplementationOfModule.empty() &&
+ Opts.CurrentModule != Opts.ImplementationOfModule) {
+ Diags.Report(diag::err_conflicting_module_names)
+ << Opts.CurrentModule << Opts.ImplementationOfModule;
+ }
if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
switch (llvm::StringSwitch<unsigned>(A->getValue())
// If we are supposed to import a module rather than including the header,
// do so now.
- if (SuggestedModule && getLangOpts().Modules) {
+ if (SuggestedModule && getLangOpts().Modules &&
+ SuggestedModule.getModule()->getTopLevelModuleName() !=
+ getLangOpts().ImplementationOfModule) {
// Compute the module access path corresponding to this module.
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule)
Diag(ImportLoc, diag::err_module_self_import)
<< Mod->getFullModuleName() << getLangOpts().CurrentModule;
+ else if (Mod->getTopLevelModuleName() == getLangOpts().ImplementationOfModule)
+ Diag(ImportLoc, diag::err_module_import_in_implementation)
+ << Mod->getFullModuleName() << getLangOpts().ImplementationOfModule;
SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
--- /dev/null
+// RUN: not %clang_cc1 -fmodule-implementation-of Foo -fmodule-name=Bar %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-IMPL-OF-ERR %s
+// CHECK-IMPL-OF-ERR: conflicting module names specified: '-fmodule-name=Bar' and '-fmodule-implementation-of Foo'
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_right -fsyntax-only
+
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_right -dM -E -o - 2>&1 | FileCheck %s
+// CHECK-NOT: __building_module
+
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_left -verify
+
+// RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -fmodule-implementation-of category_right -emit-pch -o %t.pch
+// RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t -w -Werror=auto-import %s -I %S/Inputs \
+// RUN: -DWITH_PREFIX -include-pch %t.pch -fmodule-implementation-of category_right
+
+#ifndef WITH_PREFIX
+
+@import category_left; // expected-error{{@import of module 'category_left' in implementation of 'category_left'; use #import}}
+@import category_left.sub; // expected-error{{@import of module 'category_left.sub' in implementation of 'category_left'; use #import}}
+#import "category_right.h" // expected-error{{treating}}
+#import "category_right_sub.h" // expected-error{{treating}}
+
+#endif
+