diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 940cca6736849..564ca48cc32ac 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -922,6 +922,11 @@ def err_header_import_semi_in_macro : Error< def err_header_import_not_header_unit : Error< "header file %0 (aka '%1') cannot be imported because " "it is not known to be a header unit">; +def warn_pp_include_angled_in_module_purview : Warning< + "'#include ' attaches the declarations to the named module '%0'" + ", which is not usually intended; consider moving that directive before " + "the module declaration">, + InGroup>; def warn_header_guard : Warning< "%0 is used as a header guard here, followed by #define of a different macro">, diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 6fd515a5f0c75..d97a103833c2f 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2537,6 +2537,10 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( return {ImportAction::None}; } + if (isAngled && isInNamedModule()) + Diag(FilenameTok, diag::warn_pp_include_angled_in_module_purview) + << getNamedModuleName(); + // Look up the file, create a File ID for it. SourceLocation IncludePos = FilenameTok.getLocation(); // If the filename string was the result of macro expansions, set the include diff --git a/clang/test/Preprocessor/include-in-module-purview.cppm b/clang/test/Preprocessor/include-in-module-purview.cppm new file mode 100644 index 0000000000000..0a080112b4327 --- /dev/null +++ b/clang/test/Preprocessor/include-in-module-purview.cppm @@ -0,0 +1,60 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -E -P -I%t -o %t/tmp 2>&1 | FileCheck %t/a.cppm +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -E -P -I%t -o - 2>&1 \ +// RUN: -Wno-include-angled-in-module-purview | FileCheck %t/a.cppm --check-prefix=CHECK-NO-WARN + +//--- a.h +// left empty + +//--- b.h +#include +// The headers not get included shouldn't be affected. +#ifdef WHATEVER +#include +#endif + +//--- a.cppm +module; +#include +#include +#include +#include "a.h" +#include "b.h" +export module a; + +#include +#include +#include +#include "a.h" +#include "b.h" + +// CHECK: a.cppm:9:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: a.cppm:10:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: a.cppm:11:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: In file included from {{.*}}/a.cppm:11 +// CHECK-NEXT: b.h:1:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: In file included from {{.*}}/a.cppm:13 +// CHECK-NEXT: b.h:1:10: warning: '#include ' attaches the declarations to the named module 'a' + +module :private; +#include +#include +#include +#include "a.h" +#include "b.h" + +// CHECK: a.cppm:24:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: a.cppm:25:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: a.cppm:26:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: In file included from {{.*}}/a.cppm:26 +// CHECK-NEXT: b.h:1:10: warning: '#include ' attaches the declarations to the named module 'a' +// CHECK: In file included from {{.*}}/a.cppm:28 +// CHECK-NEXT: b.h:1:10: warning: '#include ' attaches the declarations to the named module 'a' + +// We should have catched all warnings. +// CHECK: 10 warnings generated. + +// CHECK-NO-WARN-NOT: warning