]> granicus.if.org Git - clang/commitdiff
Implement the final (hopefully) wrinkle to i-c-e + builtin_constant_p
authorChris Lattner <sabre@nondot.org>
Fri, 12 Dec 2008 18:00:51 +0000 (18:00 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 12 Dec 2008 18:00:51 +0000 (18:00 +0000)
processing: it allows arbitrary foldable constants as the operand of ?: when
builtin_constant_p is the condition.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60954 91177308-0d34-0410-b5e6-96231b3b80d8

docs/InternalsManual.html
lib/AST/Expr.cpp
test/Sema/i-c-e.c

index 5d32d8df6d7dd1f7ded66bdc8bb4cdabed7cc404..531e5767582eb0f66dca64219ebc04fe19be5710 100644 (file)
@@ -1155,7 +1155,8 @@ interacts with constant evaluation:</p>
     constant expression) if the operand is any evaluatable constant.  As a
     special case, if <tt>__builtin_constant_p</tt> is the (potentially
     parenthesized) condition of a conditional operator expression ("?:"), only
-    the true side of the conditional operator is considered.</li>
+    the true side of the conditional operator is considered, and it is evaluated
+    with full constant folding.</li>
 <li><b><tt>__builtin_choose_expr</tt></b>: The condition is required to be an
     integer constant expression, but we accept any constant as an "extension of
     an extension".  This only evaluates one operand depending on which way the
index bdc5096584addb3534f13bbc369806848d7ca77e..c01c973cf592548adeedc52ccd6019cd4f2f3afd 100644 (file)
@@ -1028,14 +1028,18 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
     
     // If the condition (ignoring parens) is a __builtin_constant_p call, 
     // then only the true side is actually considered in an integer constant
-    // expression.  This is an important GNU extension.
-    //
-    // FIXME: ?: with a conditional expr should arguably be an i-c-e if the true
-    // side can be folded in any way to a constant.  See GCC PR38377 for
-    // discussion.
+    // expression, and it is fully evaluated.  This is an important GNU
+    // extension.  See GCC PR38377 for discussion.
     if (const CallExpr *CallCE = dyn_cast<CallExpr>(Cond->IgnoreParenCasts()))
-      if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
-        FalseExp = 0;
+      if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p) {
+        EvalResult EVResult;
+        if (!Evaluate(EVResult, Ctx) || EVResult.HasSideEffects)
+          return false;
+        assert(EVResult.Val.isInt() && "FP conditional expr not expected");
+        Result = EVResult.Val.getInt();
+        if (Loc) *Loc = EVResult.DiagLoc;
+        return true;
+      }
     
     // Evaluate the false one first, discard the result.
     if (FalseExp && !FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false))
index 30cc9e2dd28e4dd72da8b4c64b4a4ff591e736df..8fa840d4654a2d311329b719320df70ea4620881 100644 (file)
@@ -7,6 +7,19 @@ int expr;
 char w[__builtin_constant_p(expr) ? expr : 1];
 
 
+// __builtin_constant_p as the condition of ?: allows arbitrary foldable
+// constants to be transmogrified into i-c-e's.
+char b[__builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+2.0) : -1];
+
+struct c {
+  int a : (  // expected-error {{expression is not an integer constant expression}}
+           __builtin_constant_p((int)(1.0+2.0)) ? (int)(1.0+
+     expr  // expected-note {{subexpression not valid in an integer constant expression}}
+           ) : -1);
+};
+
+
+
 
 void test1(int n, int* p) { *(n ? p : (void *)(7-7)) = 1; }
 void test2(int n, int* p) { *(n ? p : (void *)0) = 1; }