From: Richard Smith Date: Sun, 14 Apr 2019 11:11:37 +0000 (+0000) Subject: [c++20] Enable driver and frontend support for building and using X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cab7f1f7bc141ac88d15030088b311bd450b2c94;p=clang [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 --- diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index b44a2d1d48..65f5b412d9 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -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>, DefaultError; diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 18856650a9..0d76aaaacf 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -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(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); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 9cb2ab2d5e..882d985fa0 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -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; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d1920a9ae7..febb0f942e 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -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; } diff --git a/test/CXX/module/module.unit/p8.cpp b/test/CXX/module/module.unit/p8.cpp new file mode 100644 index 0000000000..aad65272f0 --- /dev/null +++ b/test/CXX/module/module.unit/p8.cpp @@ -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 diff --git a/test/Driver/modules.cpp b/test/Driver/modules.cpp new file mode 100644 index 0000000000..4f7439cc59 --- /dev/null +++ b/test/Driver/modules.cpp @@ -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