Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

jansvoboda11
Copy link
Contributor

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.)

@jansvoboda11 jansvoboda11 requested a review from akyrtzi April 9, 2025 17:18
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 9, 2025

@llvm/pr-subscribers-clang

Author: Jan Svoboda (jansvoboda11)

Changes

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.)


Full diff: https://github.com/llvm/llvm-project/pull/135054.diff

2 Files Affected:

  • (modified) clang/lib/Lex/PPExpressions.cpp (+10)
  • (added) clang/test/Index/single-file-parse-undefined-function-like-macro.c (+15)
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

@jansvoboda11 jansvoboda11 merged commit fe2eefc into llvm:main Apr 9, 2025
14 checks passed
@jansvoboda11 jansvoboda11 deleted the single-file-parse-mode-undefined-function-like-macros branch April 9, 2025 20:00
AllinLeeYL pushed a commit to AllinLeeYL/llvm-project that referenced this pull request Apr 10, 2025
…arse mode (llvm#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.)
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…arse mode (llvm#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.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants