void updated this revision to Diff 168356.
void added a comment.

Removed unused field.


https://reviews.llvm.org/D52854

Files:
  include/clang/AST/Expr.h
  include/clang/Sema/Sema.h
  lib/AST/Expr.cpp
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaType.cpp
  test/Analysis/builtin-functions.cpp
  test/Sema/builtins.c

Index: test/Sema/builtins.c
===================================================================
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -122,6 +122,14 @@
          __builtin_constant_p(1, 2); // expected-error {{too many arguments}}
 }
 
+// __builtin_constant_p cannot resolve non-constants as a file scoped array.
+int expr;
+char y[__builtin_constant_p(expr) ? -1 : 1]; // no warning, the builtin is false.
+
+// no warning, the builtin is false.
+struct foo { int a; };
+struct foo x = (struct foo) { __builtin_constant_p(42) ? 37 : 927 };
+
 const int test17_n = 0;
 const char test17_c[] = {1, 2, 3, 0};
 const char test17_d[] = {1, 2, 3, 4};
@@ -168,14 +176,17 @@
   // a builtin.
   ASSERT(OPT("abc"));
   ASSERT(!OPT("abcd"));
+
   // In these cases, the strlen is non-constant, but the __builtin_constant_p
-  // is 0: the array size is not an ICE but is foldable.
-  ASSERT(!OPT(test17_c));        // expected-warning {{folded}}
+  // is 0: the array size is not an ICE.
+  ASSERT(!OPT(test17_c));        // no warning expected
+  ASSERT(!OPT((char*)test17_c)); // no warning expected
+  ASSERT(!OPT(test17_d));        // no warning expected
+  ASSERT(!OPT((char*)test17_d)); // no warning expected
+
+  // These are foldable.
   ASSERT(!OPT(&test17_c[0]));    // expected-warning {{folded}}
-  ASSERT(!OPT((char*)test17_c)); // expected-warning {{folded}}
-  ASSERT(!OPT(test17_d));        // expected-warning {{folded}}
   ASSERT(!OPT(&test17_d[0]));    // expected-warning {{folded}}
-  ASSERT(!OPT((char*)test17_d)); // expected-warning {{folded}}
 
 #undef OPT
 #undef T
@@ -287,3 +298,18 @@
   memcpy(buf, src, 11); // expected-warning{{'memcpy' will always overflow; destination buffer has size 10, but size argument is 11}}
   my_memcpy(buf, src, 11); // expected-warning{{'__builtin___memcpy_chk' will always overflow; destination buffer has size 10, but size argument is 11}}
 }
+
+size_t test24(int a) {
+  char x[__builtin_constant_p(a) ? -1 : 1]; // no warning expected
+  return strlen(x);
+}
+
+__attribute__((always_inline))
+size_t test25(int a) {
+  char x[__builtin_constant_p(a) ? 1 : -1]; // no warning expected
+  return strlen(x);
+}
+
+size_t test26() {
+  return test25(2);
+}
Index: test/Analysis/builtin-functions.cpp
===================================================================
--- test/Analysis/builtin-functions.cpp
+++ test/Analysis/builtin-functions.cpp
@@ -70,14 +70,14 @@
   const int j = 2;
   constexpr int k = 3;
   clang_analyzer_eval(__builtin_constant_p(42) == 1); // expected-warning {{TRUE}}
-  clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{TRUE}}
+  clang_analyzer_eval(__builtin_constant_p(i) == 0); // expected-warning {{UNKNOWN}}
   clang_analyzer_eval(__builtin_constant_p(j) == 1); // expected-warning {{TRUE}}
   clang_analyzer_eval(__builtin_constant_p(k) == 1); // expected-warning {{TRUE}}
   clang_analyzer_eval(__builtin_constant_p(i + 42) == 0); // expected-warning {{TRUE}}
   clang_analyzer_eval(__builtin_constant_p(j + 42) == 1); // expected-warning {{TRUE}}
   clang_analyzer_eval(__builtin_constant_p(k + 42) == 1); // expected-warning {{TRUE}}
   clang_analyzer_eval(__builtin_constant_p(" ") == 1); // expected-warning {{TRUE}}
-  clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{TRUE}}
+  clang_analyzer_eval(__builtin_constant_p(test_constant_p) == 0); // expected-warning {{UNKNOWN}}
   clang_analyzer_eval(__builtin_constant_p(k - 3) == 0); // expected-warning {{FALSE}}
   clang_analyzer_eval(__builtin_constant_p(k - 3) == 1); // expected-warning {{TRUE}}
 }
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -4435,6 +4435,11 @@
         checkNullabilityConsistency(S, SimplePointerKind::Array, DeclType.Loc);
       }
 
+      if (ArraySize && !D.isExpressionContext())
+        // Mark all __builtin_constant_p() calls in an array size expression as
+        // needing to be evaluated early.
+        S.MarkBuiltinConstantPCannotDelayEvaluation(ArraySize);
+
       T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals,
                            SourceRange(DeclType.Loc, DeclType.EndLoc), Name);
       break;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -5691,6 +5691,7 @@
   if (!TInfo)
     TInfo = Context.getTrivialTypeSourceInfo(literalType);
 
+  MarkBuiltinConstantPCannotDelayEvaluation(InitExpr);
   return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, InitExpr);
 }
 
@@ -5795,6 +5796,7 @@
   InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
                                                RBraceLoc);
   E->setType(Context.VoidTy); // FIXME: just a place holder for now.
+  MarkBuiltinConstantPCannotDelayEvaluation(E);
   return E;
 }
 
@@ -15585,6 +15587,50 @@
   EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E);
 }
 
+namespace {
+  // Helper class that marks  all calls to __builtin_constant_p that cannot be
+  // evaluated after inlining.
+  //
+  // GCC honors __builtin_constant_p() after inlining. Clang performs inlining
+  // too late to do that in the front-end. Therefore, clang converts bcp calls
+  // that can't be evaluated to a constant to an intrinsic so that the
+  // middle-end can determine whether or not it's constant after inlining. But
+  // this won't work for initializer lists and other constructs. For those, we
+  // need to be conservative in our analysis. So if we cannot determine that a
+  // value is constant before LLVM IR generation, then we resolve the bcp call
+  // to "false".
+  struct BuiltinConstantPCannotDelayEvaluation :
+    public EvaluatedExprVisitor<BuiltinConstantPCannotDelayEvaluation> {
+      typedef EvaluatedExprVisitor<BuiltinConstantPCannotDelayEvaluation>
+          Inherited;
+
+      BuiltinConstantPCannotDelayEvaluation(Sema &S)
+          : Inherited(S.Context) { }
+
+      void VisitCallExpr(CallExpr *E) {
+        auto DC = E->getDirectCallee();
+        if (!DC || DC->getBuiltinID() != Builtin::BI__builtin_constant_p)
+          return;
+        E->setCanDelayEvaluation(false);
+      }
+
+      void VisitInitListExpr(InitListExpr *E) {
+        for (InitListExpr::iterator II = E->begin(), IE = E->end();
+             II != IE; ++II)
+          Visit(*II);
+      }
+  };
+}
+
+// Mark all calls to __builtin_constant_p that cannot have their evaluation
+// delayed. I.e., we won't generate an llvm.is.constant() intrinsic if the front
+// end is unable to ensure the argument is constant. E.g., when a
+// __builtin_constant_p() is used in an InitListExpr or subscript of a global
+// VarDecl.
+void Sema::MarkBuiltinConstantPCannotDelayEvaluation(Expr *E) {
+  BuiltinConstantPCannotDelayEvaluation(*this).Visit(E);
+}
+
 /// Emit a diagnostic that describes an effect on the run-time behavior
 /// of the program being compiled.
 ///
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -1768,6 +1768,12 @@
   case Builtin::BI__builtin_rotateright64:
     return emitRotate(E, true);
 
+  case Builtin::BI__builtin_constant_p:
+    if (CGM.getCodeGenOpts().OptimizationLevel == 0 ||
+        hasAggregateEvaluationKind(E->getArg(0)->getType()))
+      return RValue::get(ConstantInt::get(Int32Ty, 0));
+    return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::is_constant));
+
   case Builtin::BI__builtin_object_size: {
     unsigned Type =
         E->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue();
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -8155,8 +8155,15 @@
     return Success(Val.countLeadingZeros(), E);
   }
 
-  case Builtin::BI__builtin_constant_p:
-    return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E);
+  case Builtin::BI__builtin_constant_p: {
+    auto Arg = E->getArg(0);
+    if (EvaluateBuiltinConstantP(Info.Ctx, Arg))
+      return Success(true, E);
+    if (isa<DeclRefExpr>(Arg->IgnoreParenCasts()) &&
+        E->getCanDelayEvaluation())
+      return false;
+    return Success(false, E);
+  }
 
   case Builtin::BI__builtin_ctz:
   case Builtin::BI__builtin_ctzl:
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1198,7 +1198,7 @@
     : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(),
            fn->isValueDependent(), fn->isInstantiationDependent(),
            fn->containsUnexpandedParameterPack()),
-      NumArgs(args.size()) {
+      NumArgs(args.size()), CanDelayEvaluation(true) {
 
   unsigned NumPreArgs = preargs.size();
   SubExprs = new (C) Stmt *[args.size()+PREARGS_START+NumPreArgs];
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -4098,6 +4098,7 @@
   void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
   void MarkDeclarationsReferencedInExpr(Expr *E,
                                         bool SkipLocalVariables = false);
+  void MarkBuiltinConstantPCannotDelayEvaluation(Expr *E);
 
   /// Try to recover by turning the given expression into a
   /// call.  Returns true if recovery was attempted or an error was
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -2287,6 +2287,7 @@
   Stmt **SubExprs;
   unsigned NumArgs;
   SourceLocation RParenLoc;
+  bool CanDelayEvaluation;
 
   void updateDependenciesFromArg(Expr *Arg);
 
@@ -2413,6 +2414,11 @@
   /// evaluate side-effects within its arguments.
   bool isUnevaluatedBuiltinCall(const ASTContext &Ctx) const;
 
+  // Used by __builtin_constant_p() to indicate that its evaluation can be
+  // delayed until after inlining.
+  void setCanDelayEvaluation(bool V) { CanDelayEvaluation = V; }
+  bool getCanDelayEvaluation() const { return CanDelayEvaluation; }
+
   /// getCallReturnType - Get the return type of the call expr. This is not
   /// always the type of the expr itself, if the return type is a reference
   /// type.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to