C++ Modules TS: driver support for building modules.

This works as follows: we add --precompile to the existing gamut of options for
specifying how far to go when compiling an input (-E, -c, -S, etc.). This flag
specifies that an input is taken to the precompilation step and no further, and
this can be specified when building a .pcm from a module interface or when
building a .pch from a header file.

The .cppm extension (and some related extensions) are implicitly recognized as
C++ module interface files. If --precompile is /not/ specified, the file is
compiled (via a .pcm) to a .o file containing the code for the module (and then
potentially also assembled and linked, if -S, -c, etc. are not specified). We
do not yet suppress the emission of object code for other users of the module
interface, so for now this will only work if everything in the .cppm file has
vague linkage.

As with the existing support for module-map modules, prebuilt modules can be
provided as compiler inputs either via the -fmodule-file= command-line argument
or via files named ModuleName.pcm in one of the directories specified via
-fprebuilt-module-path=.

This also exposes the -fmodules-ts cc1 flag in the driver. This is still
experimental, and in particular, the concrete syntax is subject to change as
the Modules TS evolves in the C++ committee. Unlike -fmodules, this flag does
not enable support for implicitly loading module maps nor building modules via
the module cache, but those features can be turned on separately and used in
conjunction with the Modules TS support.

llvm-svn: 280035
This commit is contained in:
Richard Smith 2016-08-30 00:44:54 +00:00
parent a819cda059
commit 88c52e0f0a
11 changed files with 113 additions and 22 deletions

View File

@ -391,8 +391,6 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration" HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
" nodes having a certain substring in a qualified name. Use" " nodes having a certain substring in a qualified name. Use"
" -ast-list to list all filterable declaration node names.">; " -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">, def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">,
HelpText<"Do not automatically generate or update the global module index">; HelpText<"Do not automatically generate or update the global module index">;
def fno_modules_error_recovery : Flag<["-"], "fno-modules-error-recovery">, def fno_modules_error_recovery : Flag<["-"], "fno-modules-error-recovery">,

View File

@ -874,6 +874,8 @@ def fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
def fimplicit_module_maps : Flag <["-"], "fimplicit-module-maps">, Group<f_Group>, def fimplicit_module_maps : Flag <["-"], "fimplicit-module-maps">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>, Flags<[DriverOption, CC1Option]>,
HelpText<"Implicitly search the file system for module map files.">; 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_maps : Flag <["-"], "fmodule-maps">, Alias<fimplicit_module_maps>;
def fmodule_name_EQ : Joined<["-"], "fmodule-name=">, Group<f_Group>, def fmodule_name_EQ : Joined<["-"], "fmodule-name=">, Group<f_Group>,
Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">, Flags<[DriverOption,CC1Option]>, MetaVarName<"<name>">,
@ -2026,6 +2028,8 @@ def _output_EQ : Joined<["--"], "output=">, Alias<o>;
def _output : Separate<["--"], "output">, Alias<o>; def _output : Separate<["--"], "output">, Alias<o>;
def _param : Separate<["--"], "param">, Group<CompileOnly_Group>; def _param : Separate<["--"], "param">, Group<CompileOnly_Group>;
def _param_EQ : Joined<["--"], "param=">, Alias<_param>; 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_EQ : Joined<["--"], "prefix=">, Alias<B>;
def _prefix : Separate<["--"], "prefix">, Alias<B>; def _prefix : Separate<["--"], "prefix">, Alias<B>;
def _preprocess : Flag<["--"], "preprocess">, Alias<E>; def _preprocess : Flag<["--"], "preprocess">, Alias<E>;

View File

@ -34,6 +34,7 @@
// a - The type should only be assembled. // a - The type should only be assembled.
// p - The type should only be precompiled. // p - The type should only be precompiled.
// u - The type can be user specified (with -x). // 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 // A - The type's temporary suffix should be appended when generating
// outputs of this type. // 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("c++-header", CXXHeader, PP_CXXHeader, "hh", "pu")
TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p") TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p")
TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, "h", "pu") 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. // Other languages.
TYPE("ada", Ada, INVALID, nullptr, "u") TYPE("ada", Ada, INVALID, nullptr, "u")

View File

@ -32,6 +32,11 @@ namespace types {
/// preprocessed. /// preprocessed.
ID getPreprocessedType(ID Id); 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 /// getTypeTempSuffix - Return the suffix to use when creating a
/// temp file of this type, or null if unspecified. /// temp file of this type, or null if unspecified.
const char *getTypeTempSuffix(ID Id, bool CLMode = false); const char *getTypeTempSuffix(ID Id, bool CLMode = false);

View File

@ -177,6 +177,10 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
(PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) {
FinalPhase = phases::Preprocess; 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. // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
(PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
@ -1685,12 +1689,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (YcArg) { if (YcArg) {
// Add a separate precompile phase for the compile phase. // Add a separate precompile phase for the compile phase.
if (FinalPhase >= phases::Compile) { if (FinalPhase >= phases::Compile) {
const types::ID HeaderInputType = types::TY_CXXHeader;
llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL; llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL;
types::getCompilationPhases(types::TY_CXXHeader, PCHPL); types::getCompilationPhases(HeaderInputType, PCHPL);
Arg *PchInputArg = MakeInputArg(Args, Opts, YcArg->getValue()); Arg *PchInputArg = MakeInputArg(Args, Opts, YcArg->getValue());
// Build the pipeline for the pch file. // Build the pipeline for the pch file.
Action *ClangClPch = C.MakeAction<InputAction>(*PchInputArg, InputType); Action *ClangClPch =
C.MakeAction<InputAction>(*PchInputArg, HeaderInputType);
for (phases::ID Phase : PCHPL) for (phases::ID Phase : PCHPL)
ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch);
assert(ClangClPch); assert(ClangClPch);
@ -1812,7 +1818,9 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args,
return C.MakeAction<PreprocessJobAction>(Input, OutputTy); return C.MakeAction<PreprocessJobAction>(Input, OutputTy);
} }
case phases::Precompile: { case phases::Precompile: {
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)) { if (Args.hasArg(options::OPT_fsyntax_only)) {
// Syntax checks should not emit a PCH file // Syntax checks should not emit a PCH file
OutputTy = types::TY_Nothing; OutputTy = types::TY_Nothing;

View File

@ -3981,6 +3981,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (JA.getType() == types::TY_Nothing) if (JA.getType() == types::TY_Nothing)
CmdArgs.push_back("-fsyntax-only"); CmdArgs.push_back("-fsyntax-only");
else if (JA.getType() == types::TY_ModuleFile)
CmdArgs.push_back("-emit-module-interface");
else if (UsePCH) else if (UsePCH)
CmdArgs.push_back("-emit-pch"); CmdArgs.push_back("-emit-pch");
else else
@ -5385,20 +5387,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fmodules enables the use of precompiled modules (off by default). // -fmodules enables the use of precompiled modules (off by default).
// Users can pass -fno-cxx-modules to turn off modules support for // Users can pass -fno-cxx-modules to turn off modules support for
// C++/Objective-C++ programs. // C++/Objective-C++ programs.
bool HaveModules = false; bool HaveClangModules = false;
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules, true); options::OPT_fno_cxx_modules, true);
if (AllowedInCXX || !types::isCXX(InputType)) { if (AllowedInCXX || !types::isCXX(InputType)) {
CmdArgs.push_back("-fmodules"); 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, // -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, 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"); CmdArgs.push_back("-fimplicit-module-maps");
} }
@ -5418,9 +5426,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fno-implicit-modules turns off implicitly compiling modules on demand. // -fno-implicit-modules turns off implicitly compiling modules on demand.
if (!Args.hasFlag(options::OPT_fimplicit_modules, if (!Args.hasFlag(options::OPT_fimplicit_modules,
options::OPT_fno_implicit_modules)) { options::OPT_fno_implicit_modules, HaveClangModules)) {
CmdArgs.push_back("-fno-implicit-modules"); if (HaveAnyModules)
} else if (HaveModules) { CmdArgs.push_back("-fno-implicit-modules");
} else if (HaveAnyModules) {
// -fmodule-cache-path specifies where our implicitly-built module files // -fmodule-cache-path specifies where our implicitly-built module files
// should be written. // should be written.
SmallString<128> Path; SmallString<128> Path;
@ -5444,7 +5453,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Path)); CmdArgs.push_back(Args.MakeArgString(Path));
} }
if (HaveModules) { if (HaveAnyModules) {
// -fprebuilt-module-path specifies where to load the prebuilt module files. // -fprebuilt-module-path specifies where to load the prebuilt module files.
for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path))
CmdArgs.push_back(Args.MakeArgString( CmdArgs.push_back(Args.MakeArgString(
@ -5460,14 +5469,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
// -fmodule-file can be used to specify files containing precompiled modules. // -fmodule-file can be used to specify files containing precompiled modules.
if (HaveModules) if (HaveAnyModules)
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
else else
Args.ClaimAllArgs(options::OPT_fmodule_file); Args.ClaimAllArgs(options::OPT_fmodule_file);
// When building modules and generating crashdumps, we need to dump a module // When building modules and generating crashdumps, we need to dump a module
// dependency VFS alongside the output. // dependency VFS alongside the output.
if (HaveModules && C.isForDiagnostics()) { if (HaveClangModules && C.isForDiagnostics()) {
SmallString<128> VFSDir(Output.getFilename()); SmallString<128> VFSDir(Output.getFilename());
llvm::sys::path::replace_extension(VFSDir, ".cache"); llvm::sys::path::replace_extension(VFSDir, ".cache");
// Add the cache directory as a temp so the crash diagnostics pick it up. // Add the cache directory as a temp so the crash diagnostics pick it up.
@ -5478,7 +5487,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(VFSDir)); CmdArgs.push_back(Args.MakeArgString(VFSDir));
} }
if (HaveModules) if (HaveClangModules)
Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path);
// Pass through all -fmodules-ignore-macro arguments. // Pass through all -fmodules-ignore-macro arguments.
@ -6019,7 +6028,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// nice to enable this when doing a crashdump for modules as well. // nice to enable this when doing a crashdump for modules as well.
if (Args.hasFlag(options::OPT_frewrite_includes, if (Args.hasFlag(options::OPT_frewrite_includes,
options::OPT_fno_rewrite_includes, false) || options::OPT_fno_rewrite_includes, false) ||
(C.isForDiagnostics() && !HaveModules)) (C.isForDiagnostics() && !HaveAnyModules))
CmdArgs.push_back("-frewrite-includes"); CmdArgs.push_back("-frewrite-includes");
// Only allow -traditional or -traditional-cpp outside in preprocessing modes. // Only allow -traditional or -traditional-cpp outside in preprocessing modes.

View File

@ -44,6 +44,14 @@ types::ID types::getPreprocessedType(ID Id) {
return getInfo(Id).PreprocessedType; 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) { const char *types::getTypeTempSuffix(ID Id, bool CLMode) {
if (Id == TY_Object && CLMode) if (Id == TY_Object && CLMode)
return "obj"; return "obj";
@ -95,6 +103,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader: case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
case TY_CXXModule: case TY_PP_CXXModule:
case TY_AST: case TY_ModuleFile: case TY_AST: case TY_ModuleFile:
case TY_LLVM_IR: case TY_LLVM_BC: case TY_LLVM_IR: case TY_LLVM_BC:
return true; 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_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias:
case TY_CXXHeader: case TY_PP_CXXHeader: case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: 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: case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE:
return true; return true;
} }
@ -183,6 +193,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("ads", TY_Ada) .Case("ads", TY_Ada)
.Case("asm", TY_PP_Asm) .Case("asm", TY_PP_Asm)
.Case("ast", TY_AST) .Case("ast", TY_AST)
.Case("ccm", TY_CXXModule)
.Case("cpp", TY_CXX) .Case("cpp", TY_CXX)
.Case("CPP", TY_CXX) .Case("CPP", TY_CXX)
.Case("c++", TY_CXX) .Case("c++", TY_CXX)
@ -200,11 +211,15 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("FPP", TY_Fortran) .Case("FPP", TY_Fortran)
.Case("gch", TY_PCH) .Case("gch", TY_PCH)
.Case("hpp", TY_CXXHeader) .Case("hpp", TY_CXXHeader)
.Case("iim", TY_PP_CXXModule)
.Case("lib", TY_Object) .Case("lib", TY_Object)
.Case("mii", TY_PP_ObjCXX) .Case("mii", TY_PP_ObjCXX)
.Case("obj", TY_Object) .Case("obj", TY_Object)
.Case("pch", TY_PCH) .Case("pch", TY_PCH)
.Case("pcm", TY_ModuleFile) .Case("pcm", TY_ModuleFile)
.Case("c++m", TY_CXXModule)
.Case("cppm", TY_CXXModule)
.Case("cxxm", TY_CXXModule)
.Default(TY_INVALID); .Default(TY_INVALID);
} }
@ -226,9 +241,11 @@ void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) {
P.push_back(phases::Preprocess); P.push_back(phases::Preprocess);
} }
if (onlyPrecompileType(Id)) { if (getPrecompiledType(Id) != TY_INVALID) {
P.push_back(phases::Precompile); P.push_back(phases::Precompile);
} else { }
if (!onlyPrecompileType(Id)) {
if (!onlyAssembleType(Id)) { if (!onlyAssembleType(Id)) {
P.push_back(phases::Compile); P.push_back(phases::Compile);
P.push_back(phases::Backend); P.push_back(phases::Backend);

View File

@ -1298,11 +1298,13 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Case("cl", IK_OpenCL) .Case("cl", IK_OpenCL)
.Case("cuda", IK_CUDA) .Case("cuda", IK_CUDA)
.Case("c++", IK_CXX) .Case("c++", IK_CXX)
.Case("c++-module", IK_CXX)
.Case("objective-c", IK_ObjC) .Case("objective-c", IK_ObjC)
.Case("objective-c++", IK_ObjCXX) .Case("objective-c++", IK_ObjCXX)
.Case("cpp-output", IK_PreprocessedC) .Case("cpp-output", IK_PreprocessedC)
.Case("assembler-with-cpp", IK_Asm) .Case("assembler-with-cpp", IK_Asm)
.Case("c++-cpp-output", IK_PreprocessedCXX) .Case("c++-cpp-output", IK_PreprocessedCXX)
.Case("c++-module-cpp-output", IK_PreprocessedCXX)
.Case("cuda-cpp-output", IK_PreprocessedCuda) .Case("cuda-cpp-output", IK_PreprocessedCuda)
.Case("objective-c-cpp-output", IK_PreprocessedObjC) .Case("objective-c-cpp-output", IK_PreprocessedObjC)
.Case("objc-cpp-output", IK_PreprocessedObjC) .Case("objc-cpp-output", IK_PreprocessedObjC)

View File

@ -546,7 +546,13 @@ bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
return false; return false;
} else if (getLangOpts().getCompilingModule() == } else if (getLangOpts().getCompilingModule() ==
LangOptions::CMK_ModuleInterface) { 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 // C11 6.9p1 says translation units must have at least one top-level

View File

@ -10,7 +10,7 @@
// CHECK-YC: -o // CHECK-YC: -o
// CHECK-YC: pchfile.pch // CHECK-YC: pchfile.pch
// CHECK-YC: -x // CHECK-YC: -x
// CHECK-YC: "c++" // CHECK-YC: "c++-header"
// 2. Use .pch file. // 2. Use .pch file.
// CHECK-YC: cc1 // CHECK-YC: cc1
// CHECK-YC: -emit-obj // CHECK-YC: -emit-obj
@ -158,7 +158,7 @@
// CHECK-YCFIFIFI: -o // CHECK-YCFIFIFI: -o
// CHECK-YCFIFIFI: foo2.pch // CHECK-YCFIFIFI: foo2.pch
// CHECK-YCFIFIFI: -x // CHECK-YCFIFIFI: -x
// CHECK-YCFIFIFI: "c++" // CHECK-YCFIFIFI: "c++-header"
// CHECK-YCFIFIFI: foo2.h // CHECK-YCFIFIFI: foo2.h
// 2. Use .pch file: Inlucdes foo2.pch and foo3.h // 2. Use .pch file: Inlucdes foo2.pch and foo3.h
// CHECK-YCFIFIFI: cc1 // CHECK-YCFIFIFI: cc1

View File

@ -0,0 +1,39 @@
// 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
// CHECK-USE-SAME: -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;