diff options
-rw-r--r-- | include/clang/Driver/CC1Options.td | 2 | ||||
-rw-r--r-- | include/clang/Driver/Options.td | 4 | ||||
-rw-r--r-- | include/clang/Driver/Types.def | 3 | ||||
-rw-r--r-- | include/clang/Driver/Types.h | 5 | ||||
-rw-r--r-- | lib/Driver/Driver.cpp | 10 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 33 | ||||
-rw-r--r-- | lib/Driver/Types.cpp | 21 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 8 | ||||
-rw-r--r-- | test/Driver/cl-pch.cpp | 4 | ||||
-rw-r--r-- | test/Driver/modules-ts.cpp | 38 |
11 files changed, 108 insertions, 22 deletions
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 104684c4ce..bfe56f9d4b 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -397,8 +397,6 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">, HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration" " nodes having a certain substring in a qualified name. Use" " -ast-list to list all filterable declaration node names.">; -def fmodules_ts : Flag <["-"], "fmodules-ts">, Group<f_Group>, - HelpText<"Enable support for the C++ Modules TS">; 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">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 987100aa3d..f0b9f5cb54 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -875,6 +875,8 @@ def fmodules : Flag <["-"], "fmodules">, Group<f_Group>, def fimplicit_module_maps : Flag <["-"], "fimplicit-module-maps">, Group<f_Group>, Flags<[DriverOption, CC1Option]>, HelpText<"Implicitly search the file system for module map files.">; +def fmodules_ts : Flag <["-"], "fmodules-ts">, Group<f_Group>, + Flags<[CC1Option]>, HelpText<"Enable support for the C++ Modules TS">; def fmodule_maps : Flag <["-"], "fmodule-maps">, Alias<fimplicit_module_maps>; def fmodule_name_EQ : Joined<["-"], "fmodule-name=">, Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">, @@ -2031,6 +2033,8 @@ def _output_EQ : Joined<["--"], "output=">, Alias<o>; def _output : Separate<["--"], "output">, Alias<o>; def _param : Separate<["--"], "param">, Group<CompileOnly_Group>; def _param_EQ : Joined<["--"], "param=">, Alias<_param>; +def _precompile : Flag<["--"], "precompile">, Flags<[DriverOption]>, + Group<Action_Group>, HelpText<"Only precompile the input">; def _prefix_EQ : Joined<["--"], "prefix=">, Alias<B>; def _prefix : Separate<["--"], "prefix">, Alias<B>; def _preprocess : Flag<["--"], "preprocess">, Alias<E>; diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index f2ff194ee6..2430b5b924 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -34,6 +34,7 @@ // a - The type should only be assembled. // p - The type should only be precompiled. // u - The type can be user specified (with -x). +// m - Precompiling this type produces a module file. // A - The type's temporary suffix should be appended when generating // outputs of this type. @@ -65,6 +66,8 @@ TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", "p") TYPE("c++-header", CXXHeader, PP_CXXHeader, "hh", "pu") TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p") TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, "h", "pu") +TYPE("c++-module", CXXModule, PP_CXXModule, "cppm", "mu") +TYPE("c++-module-cpp-output", PP_CXXModule, INVALID, "iim", "m") // Other languages. TYPE("ada", Ada, INVALID, nullptr, "u") diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h index c8f0b5664f..75780e7e1a 100644 --- a/include/clang/Driver/Types.h +++ b/include/clang/Driver/Types.h @@ -32,6 +32,11 @@ namespace types { /// preprocessed. ID getPreprocessedType(ID Id); + /// getPrecompiledType - Get the ID of the type for this input when + /// it has been precompiled, or INVALID if this input is not + /// precompiled. + ID getPrecompiledType(ID Id); + /// getTypeTempSuffix - Return the suffix to use when creating a /// temp file of this type, or null if unspecified. const char *getTypeTempSuffix(ID Id, bool CLMode = false); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index a1adb676a3..b2cd4f75a1 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -177,6 +177,10 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { FinalPhase = phases::Preprocess; + // --precompile only runs up to precompilation. + } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { + FinalPhase = phases::Precompile; + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || @@ -1814,9 +1818,9 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args, return C.MakeAction<PreprocessJobAction>(Input, OutputTy); } case phases::Precompile: { - assert(onlyPrecompileType(Input->getType()) && - "asked to precompile non-precompilable type"); - types::ID OutputTy = types::TY_PCH; + types::ID OutputTy = getPrecompiledType(Input->getType()); + assert(OutputTy != types::TY_INVALID && + "Cannot precompile this input type!"); if (Args.hasArg(options::OPT_fsyntax_only)) { // Syntax checks should not emit a PCH file OutputTy = types::TY_Nothing; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index f4dd61aed1..129b25cd21 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -3970,6 +3970,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_Nothing) CmdArgs.push_back("-fsyntax-only"); + else if (JA.getType() == types::TY_ModuleFile) + CmdArgs.push_back("-emit-module-interface"); else if (UsePCH) CmdArgs.push_back("-emit-pch"); else @@ -5380,20 +5382,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fmodules enables the use of precompiled modules (off by default). // Users can pass -fno-cxx-modules to turn off modules support for // C++/Objective-C++ programs. - bool HaveModules = false; + bool HaveClangModules = false; if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, options::OPT_fno_cxx_modules, true); if (AllowedInCXX || !types::isCXX(InputType)) { CmdArgs.push_back("-fmodules"); - HaveModules = true; + HaveClangModules = true; } } + bool HaveAnyModules = HaveClangModules; + if (Args.hasArg(options::OPT_fmodules_ts)) { + CmdArgs.push_back("-fmodules-ts"); + HaveAnyModules = true; + } + // -fmodule-maps enables implicit reading of module map files. By default, - // this is enabled if we are using precompiled modules. + // this is enabled if we are using Clang's flavor of precompiled modules. if (Args.hasFlag(options::OPT_fimplicit_module_maps, - options::OPT_fno_implicit_module_maps, HaveModules)) { + options::OPT_fno_implicit_module_maps, HaveClangModules)) { CmdArgs.push_back("-fimplicit-module-maps"); } @@ -5413,9 +5421,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fno-implicit-modules turns off implicitly compiling modules on demand. if (!Args.hasFlag(options::OPT_fimplicit_modules, - options::OPT_fno_implicit_modules)) { - CmdArgs.push_back("-fno-implicit-modules"); - } else if (HaveModules) { + options::OPT_fno_implicit_modules, HaveClangModules)) { + if (HaveAnyModules) + CmdArgs.push_back("-fno-implicit-modules"); + } else if (HaveAnyModules) { // -fmodule-cache-path specifies where our implicitly-built module files // should be written. SmallString<128> Path; @@ -5439,7 +5448,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Path)); } - if (HaveModules) { + if (HaveAnyModules) { // -fprebuilt-module-path specifies where to load the prebuilt module files. for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) CmdArgs.push_back(Args.MakeArgString( @@ -5455,14 +5464,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); // -fmodule-file can be used to specify files containing precompiled modules. - if (HaveModules) + if (HaveAnyModules) Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); else Args.ClaimAllArgs(options::OPT_fmodule_file); // When building modules and generating crashdumps, we need to dump a module // dependency VFS alongside the output. - if (HaveModules && C.isForDiagnostics()) { + if (HaveClangModules && C.isForDiagnostics()) { SmallString<128> VFSDir(Output.getFilename()); llvm::sys::path::replace_extension(VFSDir, ".cache"); // Add the cache directory as a temp so the crash diagnostics pick it up. @@ -5473,7 +5482,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(VFSDir)); } - if (HaveModules) + if (HaveClangModules) Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); // Pass through all -fmodules-ignore-macro arguments. @@ -6014,7 +6023,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || - (C.isForDiagnostics() && !HaveModules)) + (C.isForDiagnostics() && !HaveAnyModules)) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 1588c94ac7..41403811f6 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -44,6 +44,14 @@ types::ID types::getPreprocessedType(ID Id) { return getInfo(Id).PreprocessedType; } +types::ID types::getPrecompiledType(ID Id) { + if (strchr(getInfo(Id).Flags, 'm')) + return TY_ModuleFile; + if (onlyPrecompileType(Id)) + return TY_PCH; + return TY_INVALID; +} + const char *types::getTypeTempSuffix(ID Id, bool CLMode) { if (Id == TY_Object && CLMode) return "obj"; @@ -95,6 +103,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + case TY_CXXModule: case TY_PP_CXXModule: case TY_AST: case TY_ModuleFile: case TY_LLVM_IR: case TY_LLVM_BC: return true; @@ -123,6 +132,7 @@ bool types::isCXX(ID Id) { case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + case TY_CXXModule: case TY_PP_CXXModule: case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: return true; } @@ -183,6 +193,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("ads", TY_Ada) .Case("asm", TY_PP_Asm) .Case("ast", TY_AST) + .Case("ccm", TY_CXXModule) .Case("cpp", TY_CXX) .Case("CPP", TY_CXX) .Case("c++", TY_CXX) @@ -200,11 +211,15 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("FPP", TY_Fortran) .Case("gch", TY_PCH) .Case("hpp", TY_CXXHeader) + .Case("iim", TY_PP_CXXModule) .Case("lib", TY_Object) .Case("mii", TY_PP_ObjCXX) .Case("obj", TY_Object) .Case("pch", TY_PCH) .Case("pcm", TY_ModuleFile) + .Case("c++m", TY_CXXModule) + .Case("cppm", TY_CXXModule) + .Case("cxxm", TY_CXXModule) .Default(TY_INVALID); } @@ -226,9 +241,11 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) { P.push_back(phases::Preprocess); } - if (onlyPrecompileType(Id)) { + if (getPrecompiledType(Id) != TY_INVALID) { P.push_back(phases::Precompile); - } else { + } + + if (!onlyPrecompileType(Id)) { if (!onlyAssembleType(Id)) { P.push_back(phases::Compile); P.push_back(phases::Backend); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d66c5bc604..901a5a61de 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1313,11 +1313,13 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("cl", IK_OpenCL) .Case("cuda", IK_CUDA) .Case("c++", IK_CXX) + .Case("c++-module", IK_CXX) .Case("objective-c", IK_ObjC) .Case("objective-c++", IK_ObjCXX) .Case("cpp-output", IK_PreprocessedC) .Case("assembler-with-cpp", IK_Asm) .Case("c++-cpp-output", IK_PreprocessedCXX) + .Case("c++-module-cpp-output", IK_PreprocessedCXX) .Case("cuda-cpp-output", IK_PreprocessedCuda) .Case("objective-c-cpp-output", IK_PreprocessedObjC) .Case("objc-cpp-output", IK_PreprocessedObjC) diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e58e3f7c20..0bc4680e78 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -546,7 +546,13 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { return false; } else if (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface) { - Diag(Tok, diag::err_expected_module_interface_decl); + // FIXME: We avoid providing this diagnostic when generating an object file + // from an existing PCM file. This is not a good way to detect this + // condition; we should provide a mechanism to indicate whether we've + // already parsed a declaration in this translation unit and avoid calling + // ParseFirstTopLevelDecl in that case. + if (Actions.TUKind == TU_Module) + Diag(Tok, diag::err_expected_module_interface_decl); } // C11 6.9p1 says translation units must have at least one top-level diff --git a/test/Driver/cl-pch.cpp b/test/Driver/cl-pch.cpp index 19ef092685..2503c97373 100644 --- a/test/Driver/cl-pch.cpp +++ b/test/Driver/cl-pch.cpp @@ -10,7 +10,7 @@ // CHECK-YC: -o // CHECK-YC: pchfile.pch // CHECK-YC: -x -// CHECK-YC: "c++" +// CHECK-YC: "c++-header" // 2. Use .pch file. // CHECK-YC: cc1 // CHECK-YC: -emit-obj @@ -158,7 +158,7 @@ // CHECK-YCFIFIFI: -o // CHECK-YCFIFIFI: foo2.pch // CHECK-YCFIFIFI: -x -// CHECK-YCFIFIFI: "c++" +// CHECK-YCFIFIFI: "c++-header" // CHECK-YCFIFIFI: foo2.h // 2. Use .pch file: Inlucdes foo2.pch and foo3.h // CHECK-YCFIFIFI: cc1 diff --git a/test/Driver/modules-ts.cpp b/test/Driver/modules-ts.cpp new file mode 100644 index 0000000000..0fdc61b6f9 --- /dev/null +++ b/test/Driver/modules-ts.cpp @@ -0,0 +1,38 @@ +// Check compiling a module interface to a .pcm file. +// +// RUN: %clang -fmodules-ts -x c++-module --precompile %s -Dimplementation= -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE +// +// CHECK-PRECOMPILE: -cc1 {{.*}} -emit-module-interface +// CHECK-PRECOMPILE-SAME: -o {{.*}}.pcm +// CHECK-PRECOMPILE-SAME: -x c++-module +// CHECK-PRECOMPILE-SAME: modules-ts.cpp + +// Check compiling a .pcm file to a .o file. +// +// RUN: %clang -fmodules-ts %t.pcm -c -o %t.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-COMPILE +// +// CHECK-COMPILE: -cc1 {{.*}} -emit-obj +// CHECK-COMPILE-SAME: -o {{.*}}.pcm.o +// CHECK-COMPILE-SAME: -x pcm +// CHECK-COMPILE-SAME: {{.*}}.pcm + +// Check use of a .pcm file in another compilation. +// +// RUN: %clang -fmodules-ts -fmodule-file=%t.pcm %s -c -o %t.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-USE +// +// CHECK-USE: -cc1 +// CHECK-USE-SAME: -emit-obj +// CHECK-USE-SAME: -fmodule-file={{.*}}.pcm +// CHECK-USE-SAME: -o {{.*}}.o{{"?}} {{.*}}-x c++ +// CHECK-USE-SAME: modules-ts.cpp + +// Check combining precompile and compile steps works. +// +// RUN: %clang -fmodules-ts -x c++-module %s -Dimplementation= -c -o %t.pcm.o -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE --check-prefix=CHECK-COMPILE + +// Check that .cppm is treated as a module implicitly. +// RUN: cp %s %t.cppm +// RUN: %clang -fmodules-ts --precompile %t.cppm -Dimplementation= -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE + +// Note, we use -Dimplementation= to make this a valid module interface unit when building the interface. +module implementation foo; |