Skip to content
Permalink
Browse files

[c++20] Enable driver and frontend support for building and using

modules when -std=c++2a is specified.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@358355 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information...
zygoloid committed Apr 14, 2019
1 parent 33eb2ff commit cab7f1f7bc141ac88d15030088b311bd450b2c94
@@ -173,10 +173,11 @@ def note_incompatible_analyzer_plugin_api : Note<

def err_module_build_requires_fmodules : Error<
"module compilation requires '-fmodules'">;
def err_module_interface_requires_modules_ts : Error<
"module interface compilation requires '-fmodules-ts'">;
def err_module_interface_requires_cpp_modules : Error<
"module interface compilation requires '-std=c++2a' or '-fmodules-ts'">;
def err_header_module_requires_modules : Error<
"header module compilation requires '-fmodules' or '-fmodules-ts'">;
"header module compilation requires '-fmodules', '-std=c++2a', or "
"'-fmodules-ts'">;
def warn_module_config_mismatch : Warning<
"module file %0 cannot be loaded due to a configuration mismatch with the current "
"compilation">, InGroup<DiagGroup<"module-file-config-mismatch">>, DefaultError;
@@ -2721,7 +2721,7 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
}
}

HaveModules = HaveClangModules;
HaveModules |= HaveClangModules;
if (Args.hasArg(options::OPT_fmodules_ts)) {
CmdArgs.push_back("-fmodules-ts");
HaveModules = true;
@@ -4259,7 +4259,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// If a std is supplied, only add -trigraphs if it follows the
// option.
bool ImplyVCPPCXXVer = false;
if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
if (Std) {
if (Std->getOption().matches(options::OPT_ansi))
if (types::isCXX(InputType))
CmdArgs.push_back("-std=c++98");
@@ -4696,9 +4697,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes,
options::OPT_fno_double_square_bracket_attributes);

bool HaveModules = false;
RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);

// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control, false))
@@ -4765,6 +4763,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (ImplyVCPPCXXVer) {
StringRef LanguageStandard;
if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
Std = StdArg;
LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
.Case("c++14", "-std=c++14")
.Case("c++17", "-std=c++17")
@@ -4830,6 +4829,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_inline_functions))
InlineArg->render(Args, CmdArgs);

// FIXME: Find a better way to determine whether the language has modules
// support by default, or just assume that all languages do.
bool HaveModules =
Std && (Std->containsValue("c++2a") || Std->containsValue("c++latest"));
RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);

Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
options::OPT_fno_experimental_new_pass_manager);

@@ -221,8 +221,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,

bool GenerateModuleInterfaceAction::BeginSourceFileAction(
CompilerInstance &CI) {
if (!CI.getLangOpts().ModulesTS) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_modules_ts);
if (!CI.getLangOpts().ModulesTS && !CI.getLangOpts().CPlusPlusModules) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
return false;
}

@@ -239,7 +239,7 @@ GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,

bool GenerateHeaderModuleAction::PrepareToExecuteAction(
CompilerInstance &CI) {
if (!CI.getLangOpts().Modules && !CI.getLangOpts().ModulesTS) {
if (!CI.getLangOpts().Modules) {
CI.getDiagnostics().Report(diag::err_header_module_requires_modules);
return false;
}
@@ -837,7 +837,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SingleDecl = ParseModuleImport(SourceLocation());
break;
case tok::kw_export:
if (getLangOpts().ModulesTS) {
if (getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS) {
SingleDecl = ParseExportDeclaration();
break;
}
@@ -0,0 +1,40 @@
// RUN: echo 'export module foo; export int n;' > %t.cppm
// RUN: %clang_cc1 -std=c++2a %t.cppm -emit-module-interface -o %t.pcm
// RUN: %clang_cc1 -std=c++2a -fmodule-file=%t.pcm -verify -DMODE=0 %s
// RUN: %clang_cc1 -std=c++2a -fmodule-file=%t.pcm -verify -DMODE=1 %s
// RUN: %clang_cc1 -std=c++2a -fmodule-file=%t.pcm -verify -DMODE=2 %s
// RUN: %clang_cc1 -std=c++2a -fmodule-file=%t.pcm -verify -DMODE=3 %s
// RUN: %clang_cc1 -std=c++2a -fmodule-file=%t.pcm -verify -DMODE=4 %s
// RUN: %clang_cc1 -std=c++2a -fmodule-file=%t.pcm -verify -DMODE=5 %s

#if MODE == 0
// no module declaration

#elif MODE == 1
// expected-no-diagnostics
module foo;
#define IMPORTED

#elif MODE == 2
export module foo; // expected-error {{redefinition of module 'foo'}}
// expected-note-re@* {{module loaded from '{{.*}}.pcm'}}
#define IMPORTED

#elif MODE == 3
export module bar;

#elif MODE == 4
module foo:bar; // expected-error {{not yet supported}}
#define IMPORTED // FIXME

#elif MODE == 5
export module foo:bar; // expected-error {{not yet supported}} expected-error {{redefinition}} expected-note@* {{loaded from}}
#define IMPORTED // FIXME

#endif

int k = n;
#ifndef IMPORTED
// expected-error@-2 {{declaration of 'n' must be imported from module 'foo' before it is required}}
// expected-note@* {{previous}}
#endif
@@ -0,0 +1,74 @@
// RUN: rm -rf %t
// RUN: mkdir %t

// Check compiling a module interface to a .pcm file.
//
// RUN: %clang -std=c++2a -x c++-module --precompile %s -o %t/module.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++
// CHECK-PRECOMPILE-SAME: modules.cpp

// Check compiling a .pcm file to a .o file.
//
// RUN: %clang -std=c++2a %t/module.pcm -c -o %t/module.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 -std=c++2a -fmodule-file=%t/module.pcm -Dexport= %s -c -o %t/module.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.cpp

// Check combining precompile and compile steps works.
//
// RUN: %clang -std=c++2a -x c++-module %s -c -o %t/module2.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/module.cppm
// RUN: %clang -std=c++2a --precompile %t/module.cppm -o %t/module.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE

// Check compiling a header unit to a .pcm file.
//
// RUN: echo '#define FOO BAR' > %t/foo.h
// RUN: %clang -std=c++2a --precompile -x c++-header %t/foo.h -fmodule-name=header -o %t/foo.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-HEADER-UNIT
//
// CHECK-HEADER-UNIT: -cc1
// CHECK-HEADER-UNIT-SAME: -emit-header-module
// CHECK-HEADER-UNIT-SAME: -fmodule-name=header
// CHECK-HEADER-UNIT-SAME: -o {{.*}}foo.pcm
// CHECK-HEADER-UNIT-SAME: -x c++-header
// CHECK-HEADER-UNIT-SAME: foo.h

// Check use of header unit.
//
// RUN: %clang -std=c++2a -fmodule-file=%t/module.pcm -fmodule-file=%t/foo.pcm -I%t -DIMPORT -Dexport= %s -E -o - -v 2>&1 | FileCheck %s --check-prefix=CHECK-HEADER-UNIT-USE
//
// CHECK-HEADER-UNIT-USE: -cc1
// CHECK-HEADER-UNIT-USE: -E
// CHECK-HEADER-UNIT-USE: -fmodule-file={{.*}}module.pcm
// CHECK-HEADER-UNIT-USE: -fmodule-file={{.*}}foo.pcm

// Note, we use -Dexport= to make this a module implementation unit when building the implementation.
export module foo;

#ifdef IMPORT
// CHECK-HEADER-UNIT-USE: FOO;
FOO;

// CHECK-HEADER-UNIT-USE: import header.{{.*}}foo.h{{.*}};
import "foo.h";

// CHECK-HEADER-UNIT-USE: BAR;
FOO;
#endif

0 comments on commit cab7f1f

Please sign in to comment.
You can’t perform that action at this time.