[clang] [Preprocessor] Do not expand macros if the input is already preprocessed (PR #137665)
Juan Manuel Martinez CaamaƱo via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 7 08:04:42 PDT 2025
https://github.com/jmmartinez updated https://github.com/llvm/llvm-project/pull/137665
>From a701cd52fb572fb3b0f1f2f6dd96f77db632d2ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Mon, 28 Apr 2025 17:05:46 +0200
Subject: [PATCH 1/3] Pre-commit test: [Preprocessor] Do not expand macros if
the input is already preprocessed
---
.../test/Preprocessor/preprocess-cpp-output.c | 9 ++++++++
.../preprocess-pragma-cpp-output.c | 21 +++++++++++++++++++
2 files changed, 30 insertions(+)
create mode 100644 clang/test/Preprocessor/preprocess-cpp-output.c
create mode 100644 clang/test/Preprocessor/preprocess-pragma-cpp-output.c
diff --git a/clang/test/Preprocessor/preprocess-cpp-output.c b/clang/test/Preprocessor/preprocess-cpp-output.c
new file mode 100644
index 0000000000000..59ff057e9b871
--- /dev/null
+++ b/clang/test/Preprocessor/preprocess-cpp-output.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -E -x c %s | FileCheck %s --check-prefixes=EXPANDED
+// RUN: %clang_cc1 -E -x cpp-output %s | FileCheck %s --check-prefixes=EXPANDED
+
+// EXPANDED: void __attribute__((__attribute__((always_inline)))) foo()
+
+#define always_inline __attribute__((always_inline))
+void __attribute__((always_inline)) foo() {
+ return 4;
+}
diff --git a/clang/test/Preprocessor/preprocess-pragma-cpp-output.c b/clang/test/Preprocessor/preprocess-pragma-cpp-output.c
new file mode 100644
index 0000000000000..d5389374c33c5
--- /dev/null
+++ b/clang/test/Preprocessor/preprocess-pragma-cpp-output.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -E -x c %s | FileCheck %s
+// RUN: %clang_cc1 -x c -fsyntax-only %s -verify
+// RUN: %clang_cc1 -x cpp-output -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// The preprocessor does not expand macro-identifiers in #pragma directives.
+// When we preprocess & parse the code, clang expands the macros in directives.
+// When we parse already preprocessed code, clang still has to expand the
+// macros in the directives.
+// This means that we're not always able to parse the preprocessor's output
+// without preserving the definitions (-dD).
+
+#define FACTOR 4
+
+void foo() {
+ // CHECK: #pragma unroll FACTOR
+ #pragma unroll FACTOR
+ for(;;) {
+ }
+ return;
+}
>From bfe7b35697a9ad915001f5357e70d38f46c2abdc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Tue, 13 May 2025 15:03:46 +0200
Subject: [PATCH 2/3] [Modules] initializers.cpp test fix
The module contents should not contain preprocessor directives. The
contents should be already preprocessed.
Duplicate the modules instead to propose 2 versions: one with the
namespace ns and one without.
---
clang/test/Modules/initializers.cpp | 59 +++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/clang/test/Modules/initializers.cpp b/clang/test/Modules/initializers.cpp
index dcd9b08ec6f7a..e1f826fbc09f3 100644
--- a/clang/test/Modules/initializers.cpp
+++ b/clang/test/Modules/initializers.cpp
@@ -48,6 +48,7 @@
// instantiation for v<int> in one of the two headers, because we will only
// parse one of the two get() functions.
+#ifdef NS
#pragma clang module build m
module m {
module a {
@@ -60,9 +61,7 @@ module m {
#pragma clang module begin m.a
inline int non_trivial() { return 3; }
-#ifdef NS
namespace ns {
-#endif
int a = non_trivial();
inline int b = non_trivial();
@@ -102,12 +101,64 @@ inline void use(bool b, ...) {
X<int>::e<int>, X<int>::f<int>, X<int>::g<int>, X<int>::h<int>);
}
-#ifdef NS
}
-#endif
#pragma clang module end
#pragma clang module endbuild
+#else
+#pragma clang module build m
+module m {
+ module a {
+ header "foo.h" { size 123 mtime 456789 }
+ }
+ module b {}
+}
+
+#pragma clang module contents
+#pragma clang module begin m.a
+inline int non_trivial() { return 3; }
+
+int a = non_trivial();
+inline int b = non_trivial();
+thread_local int c = non_trivial();
+inline thread_local int d = non_trivial();
+
+template<typename U> int e = non_trivial();
+template<typename U> inline int f = non_trivial();
+template<typename U> thread_local int g = non_trivial();
+template<typename U> inline thread_local int h = non_trivial();
+
+inline int unused = 123; // should not be emitted
+
+template<typename T> struct X {
+ static int a;
+ static inline int b = non_trivial();
+ static thread_local int c;
+ static inline thread_local int d = non_trivial();
+
+ template<typename U> static int e;
+ template<typename U> static inline int f = non_trivial();
+ template<typename U> static thread_local int g;
+ template<typename U> static inline thread_local int h = non_trivial();
+
+ static inline int unused = 123; // should not be emitted
+};
+
+template<typename T> int X<T>::a = non_trivial();
+template<typename T> thread_local int X<T>::c = non_trivial();
+template<typename T> template<typename U> int X<T>::e = non_trivial();
+template<typename T> template<typename U> thread_local int X<T>::g = non_trivial();
+
+inline void use(bool b, ...) {
+ if (b) return;
+ use(true, e<int>, f<int>, g<int>, h<int>,
+ X<int>::a, X<int>::b, X<int>::c, X<int>::d,
+ X<int>::e<int>, X<int>::f<int>, X<int>::g<int>, X<int>::h<int>);
+}
+
+#pragma clang module end
+#pragma clang module endbuild
+#endif
#if IMPORT == 1
// Import the module and the m.a submodule; runs the ordered initializers and
>From fbe9e06e024d2de8e31501e2c481bff6f095e9a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?= <juamarti at amd.com>
Date: Tue, 22 Apr 2025 18:40:37 +0200
Subject: [PATCH 3/3] [Preprocessor] Do not expand macros if the input is
already preprocessed
---
clang/include/clang/Frontend/FrontendAction.h | 8 +++++++-
clang/include/clang/Lex/Preprocessor.h | 4 ++++
clang/lib/CodeGen/CodeGenAction.cpp | 4 +++-
clang/lib/Frontend/FrontendActions.cpp | 2 +-
clang/lib/Frontend/Rewrite/FrontendActions.cpp | 5 +++--
clang/test/Preprocessor/preprocess-cpp-output.c | 3 ++-
6 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h
index 718684a67771a..8f0bff15e47fa 100644
--- a/clang/include/clang/Frontend/FrontendAction.h
+++ b/clang/include/clang/Frontend/FrontendAction.h
@@ -84,6 +84,8 @@ class FrontendAction {
/// \return True on success; on failure ExecutionAction() and
/// EndSourceFileAction() will not be called.
virtual bool BeginSourceFileAction(CompilerInstance &CI) {
+ if (CurrentInput.isPreprocessed())
+ CI.getPreprocessor().SetMacroExpansionOnlyInDirectives();
return true;
}
@@ -98,7 +100,11 @@ class FrontendAction {
///
/// This is guaranteed to only be called following a successful call to
/// BeginSourceFileAction (and BeginSourceFile).
- virtual void EndSourceFileAction() {}
+ virtual void EndSourceFileAction() {
+ if (CurrentInput.isPreprocessed())
+ // reset the preprocessor macro expansion to the default
+ getCompilerInstance().getPreprocessor().SetEnableMacroExpansion();
+ }
/// Callback at the end of processing a single input, to determine
/// if the output files should be erased or not.
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 4d82e20e5d4f3..71b0f8eab3bfa 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1847,6 +1847,10 @@ class Preprocessor {
MacroExpansionInDirectivesOverride = true;
}
+ void SetEnableMacroExpansion() {
+ DisableMacroExpansion = MacroExpansionInDirectivesOverride = false;
+ }
+
/// Peeks ahead N tokens and returns that token without consuming any
/// tokens.
///
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 5493cc92bd8b0..5fc3c601a19f4 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -908,6 +908,8 @@ bool CodeGenAction::loadLinkModules(CompilerInstance &CI) {
bool CodeGenAction::hasIRSupport() const { return true; }
void CodeGenAction::EndSourceFileAction() {
+ ASTFrontendAction::EndSourceFileAction();
+
// If the consumer creation failed, do nothing.
if (!getCompilerInstance().hasASTConsumer())
return;
@@ -932,7 +934,7 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const {
bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) {
if (CI.getFrontendOpts().GenReducedBMI)
CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
- return true;
+ return ASTFrontendAction::BeginSourceFileAction(CI);
}
static std::unique_ptr<raw_pwrite_stream>
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index c0ab708d8b844..901cf92c73c57 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -181,7 +181,7 @@ bool GeneratePCHAction::shouldEraseOutputFiles() {
bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
CI.getLangOpts().CompilingPCH = true;
- return true;
+ return ASTFrontendAction::BeginSourceFileAction(CI);
}
std::vector<std::unique_ptr<ASTConsumer>>
diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
index 84e7a4f3f12d9..6c9c9d5b5c8d3 100644
--- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -103,12 +103,13 @@ bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
}
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
CI.getLangOpts(), FixItOpts.get()));
- return true;
+ return ASTFrontendAction::BeginSourceFileAction(CI);
}
void FixItAction::EndSourceFileAction() {
// Otherwise rewrite all files.
Rewriter->WriteFixedFiles();
+ ASTFrontendAction::EndSourceFileAction();
}
bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
@@ -298,7 +299,7 @@ bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
std::make_unique<RewriteImportsListener>(CI, OutputStream));
}
- return true;
+ return PreprocessorFrontendAction::BeginSourceFileAction(CI);
}
void RewriteIncludesAction::ExecuteAction() {
diff --git a/clang/test/Preprocessor/preprocess-cpp-output.c b/clang/test/Preprocessor/preprocess-cpp-output.c
index 59ff057e9b871..2c180601e30ac 100644
--- a/clang/test/Preprocessor/preprocess-cpp-output.c
+++ b/clang/test/Preprocessor/preprocess-cpp-output.c
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -E -x c %s | FileCheck %s --check-prefixes=EXPANDED
-// RUN: %clang_cc1 -E -x cpp-output %s | FileCheck %s --check-prefixes=EXPANDED
+// RUN: %clang_cc1 -E -x cpp-output %s | FileCheck %s --check-prefixes=NOT-EXPANDED
// EXPANDED: void __attribute__((__attribute__((always_inline)))) foo()
+// NOT-EXPANDED: void __attribute__((always_inline)) foo()
#define always_inline __attribute__((always_inline))
void __attribute__((always_inline)) foo() {
More information about the cfe-commits
mailing list