[clang] [clang][index] Handle undefined function-like macros in single file parse mode (PR #135054)

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 9 10:18:30 PDT 2025


https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/135054

The single file parse mode is supposed to enter both branches of an `#if` directive whenever the condition contains undefined identifiers. This patch adds support for undefined function-like macros, where we would previously emit an error that doesn't make sense from end-user perspective.

(I discovered this while working on a very similar feature that parses single module only and doesn't enter either `#if` branch when the condition contains undefined identifiers.)

>From 0de77a2d87f1968f0efdb57694df65b74c3fc844 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Wed, 9 Apr 2025 10:09:01 -0700
Subject: [PATCH] [clang][index] Handle undefined function-like macros in
 single file parse mode

---
 clang/lib/Lex/PPExpressions.cpp                   | 10 ++++++++++
 ...gle-file-parse-undefined-function-like-macro.c | 15 +++++++++++++++
 2 files changed, 25 insertions(+)
 create mode 100644 clang/test/Index/single-file-parse-undefined-function-like-macro.c

diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index 48835121b40e9..a202af774256a 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -26,6 +26,7 @@
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Lex/Token.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/STLExtras.h"
@@ -592,6 +593,15 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
                                      Token &PeekTok, bool ValueLive,
                                      bool &IncludedUndefinedIds,
                                      Preprocessor &PP) {
+  if (PP.getPreprocessorOpts().SingleFileParseMode && IncludedUndefinedIds) {
+    // The single-file parse mode behavior kicks in as soon as single identifier
+    // is undefined. If we've already seen one, there's no point in continuing
+    // with the rest of the expression. Besides saving work, this also prevents
+    // calling undefined function-like macros.
+    PP.DiscardUntilEndOfDirective(PeekTok);
+    return true;
+  }
+
   unsigned PeekPrec = getPrecedence(PeekTok.getKind());
   // If this token isn't valid, report the error.
   if (PeekPrec == ~0U) {
diff --git a/clang/test/Index/single-file-parse-undefined-function-like-macro.c b/clang/test/Index/single-file-parse-undefined-function-like-macro.c
new file mode 100644
index 0000000000000..4d2da1382fcd9
--- /dev/null
+++ b/clang/test/Index/single-file-parse-undefined-function-like-macro.c
@@ -0,0 +1,15 @@
+// RUN: split-file %s %t
+// RUN: c-index-test -single-file-parse %t/tu.c 2>&1 | FileCheck %t/tu.c
+
+//--- header.h
+#define FUNCTION_LIKE_MACRO() 1
+//--- tu.c
+#include "header.h"
+// CHECK-NOT: tu.c:[[@LINE+1]]:5: error: function-like macro 'FUNCTION_LIKE_MACRO' is not defined
+#if FUNCTION_LIKE_MACRO()
+// CHECK: tu.c:[[@LINE+1]]:5: FunctionDecl=then_fn
+int then_fn();
+#else
+// CHECK: tu.c:[[@LINE+1]]:5: FunctionDecl=else_fn
+int else_fn();
+#endif



More information about the cfe-commits mailing list