summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Driver/CC1Options.td2
-rw-r--r--include/clang/Driver/Options.td4
-rw-r--r--include/clang/Driver/Types.def3
-rw-r--r--include/clang/Driver/Types.h5
-rw-r--r--lib/Driver/Driver.cpp10
-rw-r--r--lib/Driver/Tools.cpp33
-rw-r--r--lib/Driver/Types.cpp21
-rw-r--r--lib/Frontend/CompilerInvocation.cpp2
-rw-r--r--lib/Parse/Parser.cpp8
-rw-r--r--test/Driver/cl-pch.cpp4
-rw-r--r--test/Driver/modules-ts.cpp38
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;