[clang] 8b020d5 - [Preprocessor] Do not expand macros if the input is already preprocessed (#137665)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 28 23:49:39 PDT 2025
Author: Juan Manuel Martinez CaamaƱo
Date: 2025-07-29T08:49:36+02:00
New Revision: 8b020d5434078145e2fd2b4f1a48bb1c78ace491
URL: https://github.com/llvm/llvm-project/commit/8b020d5434078145e2fd2b4f1a48bb1c78ace491
DIFF: https://github.com/llvm/llvm-project/commit/8b020d5434078145e2fd2b4f1a48bb1c78ace491.diff
LOG: [Preprocessor] Do not expand macros if the input is already preprocessed (#137665)
Preprocessing the preprocessor output again interacts poorly with some
flag combinations when we perform a separate preprocessing stage. In our
case, `-no-integrated-cpp -dD` triggered this issue; but I guess that
other flags could also trigger problems (`-save-temps` instead of
`-no-integrated-cpp`).
Full context (which is quite weird I'll admit):
* To cache OpenCL kernel compilation results, we use the
`-no-integrated-cpp` for the driver to generate a separate preprocessing
command (`clang -E`) before the rest of the compilation.
* Some OpenCL C language features are implemented as macro definitions
(in `opencl-c-base.h`). The semantic analysis queries the preprocessor
to check if these are defined or not, for example, when we checks if a
builtin is available when using `-fdeclare-opencl-builtins`.
* To preserve these `#define` directives, on the preprocessor's output,
we use `-dD`. However, other `#define` directives are also maintained
besides OpenCL ones; which triggers the issue shown in this PR.
A better fix for our particular case could have been to move the
language features implemented as macros into some sort of a flag to be
used together with `-fdeclare-opencl-builtins`.
But I also thought that not preprocessing preprocessor outputs seemed
like something desirable. I hope to work on this on a follow up.
Added:
clang/test/Preprocessor/preprocess-cpp-output.c
clang/test/Preprocessor/preprocess-pragma-cpp-output.c
Modified:
clang/include/clang/Frontend/FrontendAction.h
clang/include/clang/Lex/Preprocessor.h
clang/lib/CodeGen/CodeGenAction.cpp
clang/lib/Frontend/FrontendActions.cpp
clang/lib/Frontend/Rewrite/FrontendActions.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h
index 718684a67771a..08c5fbc78f8ae 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 eb5b6045510df..2c0767f3d0af6 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 dcfbd5386f3dc..685a9bbf2cde9 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
new file mode 100644
index 0000000000000..2c180601e30ac
--- /dev/null
+++ b/clang/test/Preprocessor/preprocess-cpp-output.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -E -x c %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() {
+ 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;
+}
More information about the cfe-commits
mailing list