diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b29e2e53f9385..4bc292c1fa162 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2906,6 +2906,11 @@ def fvalidate_ast_input_files_content: " Files with mismatching mtime's are considered valid" " if both contents is identical">, MarshallingInfoFlag>; +def fforce_check_cxx20_modules_input_files: + Flag <["-"], "fforce-check-cxx20-modules-input-files">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Check the input source files from C++20 modules explicitly">, + MarshallingInfoFlag>; def fmodules_validate_input_files_content: Flag <["-"], "fmodules-validate-input-files-content">, Group, Flags<[NoXarchOption]>, diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h index 6436a9b3bde20..126659f3ac002 100644 --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -211,6 +211,9 @@ class HeaderSearchOptions { // validate consistency. unsigned ValidateASTInputFilesContent : 1; + // Whether the input files from C++20 Modules should be checked. + unsigned ForceCheckCXX20ModulesInputFiles : 1; + /// Whether the module includes debug information (-gmodules). unsigned UseDebugInfo : 1; @@ -233,7 +236,8 @@ class HeaderSearchOptions { UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), ModulesValidateOncePerBuildSession(false), ModulesValidateSystemHeaders(false), - ValidateASTInputFilesContent(false), UseDebugInfo(false), + ValidateASTInputFilesContent(false), + ForceCheckCXX20ModulesInputFiles(false), UseDebugInfo(false), ModulesValidateDiagnosticOptions(true), ModulesHashContent(false), ModulesStrictContextHash(false) {} diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index a4753f525d9de..167db521a890c 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -550,12 +550,16 @@ class ASTInfoCollector : public ASTReaderListener { bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) override { - // Preserve previously set header search paths. + // llvm::SaveAndRestore doesn't support bit field. + auto ForceCheckCXX20ModulesInputFiles = + this->HSOpts.ForceCheckCXX20ModulesInputFiles; llvm::SaveAndRestore X(this->HSOpts.UserEntries); llvm::SaveAndRestore Y(this->HSOpts.SystemHeaderPrefixes); llvm::SaveAndRestore Z(this->HSOpts.VFSOverlayFiles); this->HSOpts = HSOpts; + this->HSOpts.ForceCheckCXX20ModulesInputFiles = + ForceCheckCXX20ModulesInputFiles; return false; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 8ece979f2408e..576da09095002 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2428,6 +2428,16 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // For standard C++ modules, we don't need to check the inputs. bool SkipChecks = F.StandardCXXModule; + const HeaderSearchOptions &HSOpts = + PP.getHeaderSearchInfo().getHeaderSearchOpts(); + + // The option ForceCheckCXX20ModulesInputFiles is only meaningful for C++20 + // modules. + if (F.StandardCXXModule && HSOpts.ForceCheckCXX20ModulesInputFiles) { + SkipChecks = false; + Overridden = false; + } + OptionalFileEntryRefDegradesToFileEntryPtr File = OptionalFileEntryRef( expectedToOptional(FileMgr.getFileRef(Filename, /*OpenFile=*/false))); diff --git a/clang/test/Modules/cxx20-force-check-input.cppm b/clang/test/Modules/cxx20-force-check-input.cppm new file mode 100644 index 0000000000000..4611f8f7cafa1 --- /dev/null +++ b/clang/test/Modules/cxx20-force-check-input.cppm @@ -0,0 +1,33 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUN: %t/a.cppm -emit-module-interface -o %t/a.pcm +// +// RUN: echo "inline int bar = 46;" >> %t/foo.h +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUNX: %t/use.cpp -fmodule-file=a=%t/a.pcm -verify -fsyntax-only +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUNX: %t/a.pcm -emit-llvm -o - | FileCheck %t/a.ll +// +// RUN: echo "export int var = 43;" >> %t/a.cppm +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUNX: %t/use.cpp -fmodule-file=a=%t/a.pcm -verify -fsyntax-only +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUNX: %t/a.pcm -emit-llvm -o - | FileCheck %t/a.ll +// +// RUN: not %clang_cc1 -std=c++20 -triple %itanium_abi_triple \ +// RUN: -fforce-check-cxx20-modules-input-files %t/a.pcm \ +// RUN: -emit-llvm -o - 2>&1 | FileCheck %t/a.cppm -check-prefix=CHECK-FAILURE + +//--- foo.h +inline int foo = 43; + +//--- a.cppm +// expected-no-diagnostics +module; +#include "foo.h" +export module a; +export using ::foo; + +// CHECK-FAILURE: fatal error:{{.*}}a.cppm' has been modified since the AST file {{.*}}was built