[clang][index] Handle undefined function-like macros in single file parse mode (#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.)
This commit is contained in:
Jan Svoboda 2025-04-09 13:00:17 -07:00 committed by GitHub
parent 5709506de0
commit fe2eefc471
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 0 deletions

View File

@ -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) {

View File

@ -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