From b537a3a651803cd11edf0e5c33f6cfa397dd9d10 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Wed, 23 Jul 2014 15:30:23 +0000 Subject: [PATCH] Add stopgap option -fmodule-implementation-of This flag specifies that we are building an implementation file of the module , preventing importing as a module. This does not consider this to be the 'current module' for the purposes of doing modular checks like decluse or non-modular-include warnings, unlike -fmodule-name. This is needed as a stopgap until: 1) we can resolve relative includes to a VFS-mapped module (or can safely import a header textually and as part of a module) and ideally 2) we can safely do incremental rebuilding when implementation files import submodules. llvm-svn: 213767 --- .../include/clang/Basic/DiagnosticFrontendKinds.td | 4 +++ clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/include/clang/Basic/LangOptions.h | 5 ++++ clang/include/clang/Driver/CC1Options.td | 3 +++ clang/lib/Basic/LangOptions.cpp | 1 + clang/lib/Frontend/CompilerInstance.cpp | 10 ++++++-- clang/lib/Frontend/CompilerInvocation.cpp | 8 ++++++ clang/lib/Lex/PPDirectives.cpp | 4 ++- clang/lib/Sema/SemaDecl.cpp | 3 +++ clang/test/Modules/implementation-of-module.m | 29 ++++++++++++++++++++++ 10 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 clang/test/Modules/implementation-of-module.m diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index ab0c6cf..bbe0fa7 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -178,6 +178,10 @@ def note_module_def_undef_here : Note< def remark_module_build : Remark<"building module '%0' as '%1'">, InGroup>, 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< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6d781f9..85072f1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7212,6 +7212,8 @@ def err_module_import_not_at_top_level : 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 { diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 9bffc7c..fb406a2 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -88,6 +88,11 @@ public: /// \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; diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index d25560c..c3685e0 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -327,6 +327,9 @@ def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">, 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<"">, + HelpText<"Specify the name of the module whose implementation file this is">; let Group = Action_Group in { diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index f8714b2..ae1c799 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -36,5 +36,6 @@ void LangOptions::resetNonModularOptions() { Sanitize = SanitizerOptions::Disabled; CurrentModule.clear(); + ImplementationOfModule.clear(); } diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 6af920d..4a75058 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1265,7 +1265,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // 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; @@ -1279,7 +1280,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, 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; @@ -1448,6 +1450,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, 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. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2025871..0c6d77d 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1495,6 +1495,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, 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(A->getValue()) diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 1741c30..a8e27c7 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1539,7 +1539,9 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // 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? diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index bbe6930..9ce0928 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13438,6 +13438,9 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, 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 IdentifierLocs; Module *ModCheck = Mod; diff --git a/clang/test/Modules/implementation-of-module.m b/clang/test/Modules/implementation-of-module.m new file mode 100644 index 0000000..b398404 --- /dev/null +++ b/clang/test/Modules/implementation-of-module.m @@ -0,0 +1,29 @@ +// 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 + -- 2.7.4