diff --git a/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h b/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h index 9bb820156c2524..121ca893e314f4 100644 --- a/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h +++ b/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h @@ -39,6 +39,9 @@ enum TokenKind { pp_import, pp_pragma_import, pp_pragma_once, + pp_pragma_push_macro, + pp_pragma_pop_macro, + pp_pragma_include_alias, pp_include_next, pp_if, pp_ifdef, diff --git a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp index f5cbd5e51b9b95..f597c56837fb48 100644 --- a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp +++ b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp @@ -734,6 +734,27 @@ bool Minimizer::lexPragma(const char *&First, const char *const End) { append("#pragma once\n"); return false; } + if (FoundId.Name == "push_macro") { + // #pragma push_macro + makeToken(pp_pragma_push_macro); + append("#pragma push_macro"); + printDirectiveBody(First, End); + return false; + } + if (FoundId.Name == "pop_macro") { + // #pragma pop_macro + makeToken(pp_pragma_pop_macro); + append("#pragma pop_macro"); + printDirectiveBody(First, End); + return false; + } + if (FoundId.Name == "include_alias") { + // #pragma include_alias + makeToken(pp_pragma_include_alias); + append("#pragma include_alias"); + printDirectiveBody(First, End); + return false; + } if (FoundId.Name != "clang") { skipLine(First, End); @@ -835,6 +856,10 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { // Figure out the token. IdInfo Id = lexIdentifier(First, End); First = Id.Last; + + if (Id.Name == "pragma") + return lexPragma(First, End); + auto Kind = llvm::StringSwitch(Id.Name) .Case("include", pp_include) .Case("__include_macros", pp___include_macros) @@ -850,7 +875,6 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { .Case("elifndef", pp_elifndef) .Case("else", pp_else) .Case("endif", pp_endif) - .Case("pragma", pp_pragma_import) .Default(pp_none); if (Kind == pp_none) { skipDirective(Id.Name, First, End); @@ -863,9 +887,6 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { if (Kind == pp_define) return lexDefine(First, End); - if (Kind == pp_pragma_import) - return lexPragma(First, End); - // Everything else. return lexDefault(Kind, Id.Name, First, End); } diff --git a/clang/test/ClangScanDeps/Inputs/preprocess_minimized_pragmas.h b/clang/test/ClangScanDeps/Inputs/preprocess_minimized_pragmas.h new file mode 100644 index 00000000000000..f0d6b090991b3c --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/preprocess_minimized_pragmas.h @@ -0,0 +1,27 @@ +// #pragma push_macro/pop_macro +#define INCLUDE_A +#pragma push_macro("INCLUDE_A") +#undef INCLUDE_A +#pragma pop_macro("INCLUDE_A") + +#ifdef INCLUDE_A +#include "a.h" +#endif + +// #pragma push_macro/pop_macro with argument macro expansion +#define INCLUDE_B +#define MACRO_NAME "INCLUDE_B" + +#pragma push_macro(MACRO_NAME) +#undef INCLUDE_B +#pragma pop_macro(MACRO_NAME) + +#ifdef INCLUDE_B +#include "b.h" +#endif + +// #pragma include_alias (MS specific) +// When compiling without MS Extensions, the pragma is not recognized, +// and the file c_alias.h is included instead of c.h +#pragma include_alias("c_alias.h", "c.h") +#include "c_alias.h" diff --git a/clang/test/ClangScanDeps/Inputs/preprocess_minimized_pragmas_cdb.json b/clang/test/ClangScanDeps/Inputs/preprocess_minimized_pragmas_cdb.json new file mode 100644 index 00000000000000..f642b94c1d9bc7 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/preprocess_minimized_pragmas_cdb.json @@ -0,0 +1,12 @@ +[ +{ + "directory": "DIR", + "command": "clang -E DIR/preprocess_minimized_pragmas_basic.cpp -IInputs -target x86_64-linux", + "file": "DIR/preprocess_minimized_pragmas_basic.cpp" +}, +{ + "directory": "DIR", + "command": "clang -E DIR/preprocess_minimized_pragmas_ms.cpp -IInputs -target x86_64-windows", + "file": "DIR/preprocess_minimized_pragmas_ms.cpp" +} +] diff --git a/clang/test/ClangScanDeps/preprocess_minimized_pragmas.cpp b/clang/test/ClangScanDeps/preprocess_minimized_pragmas.cpp new file mode 100644 index 00000000000000..fa906f94df9ea0 --- /dev/null +++ b/clang/test/ClangScanDeps/preprocess_minimized_pragmas.cpp @@ -0,0 +1,32 @@ +// RUN: rm -rf %t.dir +// RUN: rm -rf %t.cdb +// RUN: mkdir -p %t.dir +// RUN: cp %s %t.dir/preprocess_minimized_pragmas_basic.cpp +// RUN: cp %s %t.dir/preprocess_minimized_pragmas_ms.cpp +// RUN: mkdir %t.dir/Inputs +// RUN: cp %S/Inputs/preprocess_minimized_pragmas.h %t.dir/Inputs/preprocess_minimized_pragmas.h +// RUN: touch %t.dir/Inputs/a.h +// RUN: touch %t.dir/Inputs/b.h +// RUN: touch %t.dir/Inputs/c.h +// RUN: touch %t.dir/Inputs/c_alias.h +// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/preprocess_minimized_pragmas_cdb.json > %t.cdb +// +// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess-minimized-sources | \ +// RUN: FileCheck %s +// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess | \ +// RUN: FileCheck %s + +#include "preprocess_minimized_pragmas.h" + +// CHECK: preprocess_minimized_pragmas_basic.cpp +// CHECK-NEXT: Inputs{{/|\\}}preprocess_minimized_pragmas.h +// CHECK-NEXT: Inputs{{/|\\}}a.h +// CHECK-NEXT: Inputs{{/|\\}}b.h +// Expect include aliasing alias "c_alias.h" -> "c.h" to fail when Microsoft extensions are off. +// CHECK-NEXT: Inputs{{/|\\}}c_alias.h + +// CHECK: preprocess_minimized_pragmas_ms.cpp +// CHECK-NEXT: Inputs{{/|\\}}preprocess_minimized_pragmas.h +// CHECK-NEXT: Inputs{{/|\\}}a.h +// CHECK-NEXT: Inputs{{/|\\}}b.h +// CHECK-NEXT: Inputs{{/|\\}}c.h diff --git a/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c b/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c new file mode 100644 index 00000000000000..98b1cc88e7c18e --- /dev/null +++ b/clang/test/Lexer/minimize_source_to_dependency_directives_pragmas.c @@ -0,0 +1,21 @@ +// Test that the required #pragma directives are minimized +// RUN: %clang_cc1 -print-dependency-directives-minimized-source %s 2>&1 | FileCheck %s + +#pragma once + +// some pragmas not needed in minimized source. +#pragma region TestRegion +#pragma endregion +#pragma warning "message" + +// pragmas required in the minimized source. +#pragma push_macro( "MYMACRO" ) +#pragma pop_macro("MYMACRO") +#pragma clang module import mymodule +#pragma include_alias(, "mystring.h") + +// CHECK: #pragma once +// CHECK-NEXT: #pragma push_macro( "MYMACRO" ) +// CHECK-NEXT: #pragma pop_macro("MYMACRO") +// CHECK-NEXT: #pragma clang module import mymodule +// CHECK-NEXT: #pragma include_alias(, "mystring.h") diff --git a/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp b/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp index 81945cf4618c13..d65c8de7f0e19f 100644 --- a/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp @@ -63,6 +63,9 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) { "#import \n" "@import A;\n" "#pragma clang module import A\n" + "#pragma push_macro(A)\n" + "#pragma pop_macro(A)\n" + "#pragma include_alias(, )\n" "export module m;\n" "import m;\n", Out, Tokens)); @@ -82,10 +85,13 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) { EXPECT_EQ(pp_import, Tokens[13].K); EXPECT_EQ(decl_at_import, Tokens[14].K); EXPECT_EQ(pp_pragma_import, Tokens[15].K); - EXPECT_EQ(cxx_export_decl, Tokens[16].K); - EXPECT_EQ(cxx_module_decl, Tokens[17].K); - EXPECT_EQ(cxx_import_decl, Tokens[18].K); - EXPECT_EQ(pp_eof, Tokens[19].K); + EXPECT_EQ(pp_pragma_push_macro, Tokens[16].K); + EXPECT_EQ(pp_pragma_pop_macro, Tokens[17].K); + EXPECT_EQ(pp_pragma_include_alias, Tokens[18].K); + EXPECT_EQ(cxx_export_decl, Tokens[19].K); + EXPECT_EQ(cxx_module_decl, Tokens[20].K); + EXPECT_EQ(cxx_import_decl, Tokens[21].K); + EXPECT_EQ(pp_eof, Tokens[22].K); } TEST(MinimizeSourceToDependencyDirectivesTest, Define) { @@ -406,6 +412,22 @@ TEST(MinimizeSourceToDependencyDirectivesTest, Pragma) { ASSERT_FALSE(minimizeSourceToDependencyDirectives("#pragma A\n", Out)); EXPECT_STREQ("", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + "#pragma push_macro(\"MACRO\")\n", Out)); + EXPECT_STREQ("#pragma push_macro(\"MACRO\")\n", Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + "#pragma pop_macro(\"MACRO\")\n", Out)); + EXPECT_STREQ("#pragma pop_macro(\"MACRO\")\n", Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + "#pragma include_alias(\"A\", \"B\")\n", Out)); + EXPECT_STREQ("#pragma include_alias(\"A\", \"B\")\n", Out.data()); + + ASSERT_FALSE(minimizeSourceToDependencyDirectives( + "#pragma include_alias(, )\n", Out)); + EXPECT_STREQ("#pragma include_alias(, )\n", Out.data()); + ASSERT_FALSE(minimizeSourceToDependencyDirectives("#pragma clang\n", Out)); EXPECT_STREQ("", Out.data());