[clang] Clang/Preprocessor: Support short circuit in directive (PR #123912)

YunQiang Su via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 22 02:34:43 PST 2025


https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/123912

>From f0010f932ae3c89651c631736a7aa495027e8fdc Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Wed, 22 Jan 2025 09:04:44 +0000
Subject: [PATCH] Clang/Preprocessor: Support short circuit in directive

Don't Evaluate RHS in if directive when short circuit.
Examples include
   #if 0 && another_condition
   #if 1 || another_condition
---
 clang/lib/Lex/PPExpressions.cpp               | 28 ++++++-
 clang/test/C/drs/dr2xx.c                      |  2 +-
 ...wavefront-size-deprecation-diagnostics.hip |  2 +-
 .../Preprocessor/directive-short-circuit.c    | 74 +++++++++++++++++++
 4 files changed, 103 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/Preprocessor/directive-short-circuit.c

diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index a3b1384f0fa1d6..7e413ec6076642 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -624,7 +624,33 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
 
     // Consume the operator, remembering the operator's location for reporting.
     SourceLocation OpLoc = PeekTok.getLocation();
-    PP.LexNonComment(PeekTok);
+
+    if (!RHSIsLive && (Operator == tok::ampamp || Operator == tok::pipepipe)) {
+      unsigned ThisPrec = PeekPrec;
+      while (true) {
+        PP.LexUnexpandedNonComment(PeekTok);
+        if (PeekTok.is(tok::l_paren)) {
+          unsigned NestParen = 1;
+          while (true) {
+            PP.LexUnexpandedNonComment(PeekTok);
+            if (PeekTok.is(tok::l_paren))
+              NestParen++;
+            else if (PeekTok.is(tok::r_paren))
+              NestParen--;
+            if (NestParen == 0)
+              break;
+          }
+          PP.LexUnexpandedNonComment(PeekTok);
+        }
+        PeekPrec = getPrecedence(PeekTok.getKind());
+        if (PeekPrec <= ThisPrec) {
+          LHS.setEnd(PeekTok.getEndLoc());
+          break;
+        }
+      }
+      continue;
+    } else
+      PP.LexNonComment(PeekTok);
 
     PPValue RHS(LHS.getBitWidth());
     // Parse the RHS of the operator.
diff --git a/clang/test/C/drs/dr2xx.c b/clang/test/C/drs/dr2xx.c
index ffdf5aac377d97..a1e24257f2e8ed 100644
--- a/clang/test/C/drs/dr2xx.c
+++ b/clang/test/C/drs/dr2xx.c
@@ -258,7 +258,7 @@ void dr252(void) {
 void dr258(void) {
   /* We get the diagnostic twice because the argument is used twice in the
    * expansion. */
-#define repeat(x) x && x
+#define repeat(x) x || x
 #if repeat(defined fred) /* expected-warning 2 {{macro expansion producing 'defined' has undefined behavior}} */
 #endif
 
diff --git a/clang/test/Driver/hip-wavefront-size-deprecation-diagnostics.hip b/clang/test/Driver/hip-wavefront-size-deprecation-diagnostics.hip
index 8a60f5a150048f..dcd0b4f6f9fdd6 100644
--- a/clang/test/Driver/hip-wavefront-size-deprecation-diagnostics.hip
+++ b/clang/test/Driver/hip-wavefront-size-deprecation-diagnostics.hip
@@ -23,7 +23,7 @@ template<int N> __attribute__((host, device)) int templatify(int x) {
 __attribute__((device)) const int GlobalConst = __AMDGCN_WAVEFRONT_SIZE__; // expected-warning {{macro '__AMDGCN_WAVEFRONT_SIZE__' has been marked as deprecated}}
 constexpr int GlobalConstExpr = __AMDGCN_WAVEFRONT_SIZE__; // expected-warning {{macro '__AMDGCN_WAVEFRONT_SIZE__' has been marked as deprecated}}
 
-#if defined(__HIP_DEVICE_COMPILE__) && (__AMDGCN_WAVEFRONT_SIZE__ == 64) // expected-warning {{macro '__AMDGCN_WAVEFRONT_SIZE__' has been marked as deprecated}}
+#if (__AMDGCN_WAVEFRONT_SIZE__ == 64) && defined(__HIP_DEVICE_COMPILE__) // expected-warning {{macro '__AMDGCN_WAVEFRONT_SIZE__' has been marked as deprecated}}
 int foo(void);
 #endif
 
diff --git a/clang/test/Preprocessor/directive-short-circuit.c b/clang/test/Preprocessor/directive-short-circuit.c
new file mode 100644
index 00000000000000..d137f8198cbbcf
--- /dev/null
+++ b/clang/test/Preprocessor/directive-short-circuit.c
@@ -0,0 +1,74 @@
+// RUN: %clang -E -MD -MF - %s | FileCheck -check-prefix ZERO_AND_HAS_INCLUDE %s
+//
+// ZERO_AND_HAS_INCLUDE-NOT: limits.h
+//
+#if 0 && __has_include(<limits.h>)
+#include <limits.h>
+#endif
+
+#if 4==5 && __has_include(<limits.h>)
+#include <limits.h>
+#endif
+
+#if defined(_THIS_IS_NOT_DEFINED) && __has_include(<limits.h>)
+#include <limits.h>
+#endif
+
+#if 0 && (__has_include(<limits.h>))
+#include <limits.h>
+#endif
+
+#if 4==5 && (__has_include(<limits.h>))
+#include <limits.h>
+#endif
+
+#if defined(_THIS_IS_NOT_DEFINED) && (__has_include(<limits.h>))
+#include <limits.h>
+#endif
+
+#if 0 && (5==5 && __has_include(<limits.h>))
+#include <limits.h>
+#endif
+
+#if 1 && (4==5 && __has_include(<limits.h>))
+#include <limits.h>
+#endif
+
+
+
+
+
+
+#if 1 || __has_include(<limits.h>)
+XXXXXXXXXX
+#endif
+#if 5==5 || __has_include(<limits.h>)
+XXXXXXXXXX
+#endif
+
+#if defined(__clang__) || __has_include(<limits.h>)
+XXXXXXXXXX
+#endif
+
+#if 1 || (__has_include(<limits.h>))
+#endif
+
+#if 5==5 || (__has_include(<limits.h>))
+XXXXXXXXXX
+#endif
+
+#if defined(__clang__) || (__has_include(<limits.h>))
+XXXXXXXXXX
+#endif
+
+#if 1 && (5==5 || __has_include(<limits.h>))
+XXXXXXXXXX
+#endif
+
+#if 1 || (5==5 || __has_include(<limits.h>))
+XXXXXXXXXX
+#endif
+
+#if 0 || (5==5 || __has_include(<limits.h>))
+XXXXXXXXXX
+#endif



More information about the cfe-commits mailing list