-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Clang/Preprocessor: Support short circuit in directive #123912
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
|
@llvm/pr-subscribers-clang-driver @llvm/pr-subscribers-clang Author: YunQiang Su (wzssyqa) ChangesDon't Evaluate RHS in if directive when short circuit. Examples include Full diff: https://github.com/llvm/llvm-project/pull/123912.diff 2 Files Affected:
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/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
|
|
Can you explain the motivation for this change? Thanks |
|
It's an alternative to #120673 This resolves my concerns with the original patch, and I'm pretty sure it doesn't cause any other issues for just parsing, but I do plan to take a closer look in a bit. |
Don't Evaluate RHS in if directive when short circuit. Examples include #if 0 && another_condition #if 1 || another_condition
43ec3fe to
f0010f9
Compare
One example is as we talked in #120673 will introduce |
| 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}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errr, I think this change shows a bug with the RUN line. Should it be passing -fcuda-is-device so that __HIP_DEVICE_COMPILE__ is actually defined? CC @ritter-x2a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AaronBallman thanks for notifying me! I think -fcuda-is-device isn't necessary; as far as I'm aware (I just tried) the second RUN line with --offload-device-only leads to a clang run with __HIP_DEVICE_COMPILE__ defined to 1.
I'd prefer if we left this expression in the test as it was and changed the expected-warning comment behind it to an ondevice-warning and used -verify=expected,ondevice in the second RUN line instead, if we change preprocessing such that the deprecation warning isn't triggered due to short-circuit evaluation.
| #endif | ||
|
|
||
|
|
||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens with code like:
#if 0 && absolute garbage goes here
#endif
Do we still get an error for the incorrect code after the &&?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No error message will emit here.
|
I think it would be more useful in practice if the deprecation warnings respected lazy evaluation, as the PR suggests, but it's worth noting that this deviates from the C Standard, which specifies that macros are replaced first, before short-circuit evaluation takes place. |
Ooof, that's a really good point. C23 6.10.2p13:
|
|
Thanks. So this patch is incorrect. Let's close it. |
Don't Evaluate RHS in if directive when short circuit. Examples include
#if 0 && another_condition
#if 1 || another_condition