[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-04-23 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC359067: [Builtins] Implement __builtin_is_constant_evaluated 
for use in C++2a (authored by EricWF, committed by ).
Herald added a project: clang.

Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500

Files:
  include/clang/Basic/Builtins.def
  lib/AST/ExprConstant.cpp
  lib/Basic/Builtins.cpp
  lib/CodeGen/CGDecl.cpp
  test/CodeGenCXX/builtin-is-constant-evaluated.cpp
  test/Sema/builtins.c
  test/SemaCXX/builtin-is-constant-evaluated.cpp

Index: lib/CodeGen/CGDecl.cpp
===
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -1783,7 +1783,8 @@
   }
 
   llvm::Constant *constant = nullptr;
-  if (emission.IsConstantAggregate || D.isConstexpr()) {
+  if (emission.IsConstantAggregate || D.isConstexpr() ||
+  D.isUsableInConstantExpressions(getContext())) {
 assert(!capturedByInit && "constant init contains a capturing block?");
 constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D);
 if (constant && trivialAutoVarInit !=
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -8279,6 +8279,9 @@
 return Success(false, E);
   }
 
+  case Builtin::BI__builtin_is_constant_evaluated:
+return Success(Info.InConstantContext, E);
+
   case Builtin::BI__builtin_ctz:
   case Builtin::BI__builtin_ctzl:
   case Builtin::BI__builtin_ctzll:
@@ -11139,6 +11142,7 @@
   EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
   EvalInfo Info(Ctx, Result, EM);
   Info.InConstantContext = true;
+
   if (!::Evaluate(Result.Val, Info, this))
 return false;
 
Index: lib/Basic/Builtins.cpp
===
--- lib/Basic/Builtins.cpp
+++ lib/Basic/Builtins.cpp
@@ -75,9 +75,12 @@
   bool OclCUnsupported = !LangOpts.OpenCL &&
  (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES);
   bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG;
+  bool CPlusPlusUnsupported =
+  !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG;
   return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported &&
  !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported &&
- !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported;
+ !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported &&
+ !CPlusPlusUnsupported;
 }
 
 /// initializeBuiltins - Mark the identifiers for all the builtins with their
Index: include/clang/Basic/Builtins.def
===
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -500,6 +500,7 @@
 BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
 BUILTIN(__builtin_thread_pointer, "v*", "nc")
 BUILTIN(__builtin_launder, "v*v*", "nt")
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "n", CXX_LANG)
 
 // GCC exception builtins
 BUILTIN(__builtin_eh_return, "vzv*", "r") // FIXME: Takes intptr_t, not size_t!
Index: test/SemaCXX/builtin-is-constant-evaluated.cpp
===
--- test/SemaCXX/builtin-is-constant-evaluated.cpp
+++ test/SemaCXX/builtin-is-constant-evaluated.cpp
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+using size_t = decltype(sizeof(int));
+
+namespace std {
+inline constexpr bool is_constant_evaluated() noexcept {
+  return __builtin_is_constant_evaluated();
+}
+} // namespace std
+
+extern int dummy; // expected-note 1+ {{declared here}}
+
+static_assert(__builtin_is_constant_evaluated());
+static_assert(noexcept(__builtin_is_constant_evaluated()));
+
+constexpr bool b = __builtin_is_constant_evaluated();
+static_assert(b);
+
+const int n = __builtin_is_constant_evaluated() ? 4 : dummy;
+static_assert(n == 4);
+constexpr int cn = __builtin_is_constant_evaluated() ? 11 : dummy;
+static_assert(cn == 11);
+// expected-error@+1 {{'bn' must be initialized by a constant expression}}
+constexpr int bn = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{non-const variable 'dummy' is not allowed}}
+
+const int n2 = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{declared here}}
+static_assert(n2 == 42);   // expected-error {{static_assert expression is not an integral constant}}
+// expected-note@-1 {{initializer of 'n2' is not a constant expression}}
+
+template 
+struct Templ { static_assert(V); static_assert(Default); };
+Templ<__builtin_is_constant_evaluated()> x; // type X
+
+template 
+void test_if_constexpr() {
+  if constexpr (__builtin_is_constant_evaluated()) {
+static_assert(__is_same(T, int));
+  } else {
+using Test = 

[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-04-23 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 196368.
EricWF added a comment.

- Merge with master.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500

Files:
  include/clang/Basic/Builtins.def
  lib/AST/ExprConstant.cpp
  lib/Basic/Builtins.cpp
  lib/CodeGen/CGDecl.cpp
  test/CodeGenCXX/builtin-is-constant-evaluated.cpp
  test/Sema/builtins.c
  test/SemaCXX/builtin-is-constant-evaluated.cpp

Index: test/SemaCXX/builtin-is-constant-evaluated.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-is-constant-evaluated.cpp
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+using size_t = decltype(sizeof(int));
+
+namespace std {
+inline constexpr bool is_constant_evaluated() noexcept {
+  return __builtin_is_constant_evaluated();
+}
+} // namespace std
+
+extern int dummy; // expected-note 1+ {{declared here}}
+
+static_assert(__builtin_is_constant_evaluated());
+static_assert(noexcept(__builtin_is_constant_evaluated()));
+
+constexpr bool b = __builtin_is_constant_evaluated();
+static_assert(b);
+
+const int n = __builtin_is_constant_evaluated() ? 4 : dummy;
+static_assert(n == 4);
+constexpr int cn = __builtin_is_constant_evaluated() ? 11 : dummy;
+static_assert(cn == 11);
+// expected-error@+1 {{'bn' must be initialized by a constant expression}}
+constexpr int bn = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{non-const variable 'dummy' is not allowed}}
+
+const int n2 = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{declared here}}
+static_assert(n2 == 42);   // expected-error {{static_assert expression is not an integral constant}}
+// expected-note@-1 {{initializer of 'n2' is not a constant expression}}
+
+template 
+struct Templ { static_assert(V); static_assert(Default); };
+Templ<__builtin_is_constant_evaluated()> x; // type X
+
+template 
+void test_if_constexpr() {
+  if constexpr (__builtin_is_constant_evaluated()) {
+static_assert(__is_same(T, int));
+  } else {
+using Test = typename T::DOES_NOT_EXIST;
+  }
+}
+template void test_if_constexpr();
+
+void test_array_decl() {
+  char x[__builtin_is_constant_evaluated() + std::is_constant_evaluated()];
+  static_assert(sizeof(x) == 2, "");
+}
+
+void test_case_stmt(int x) {
+  switch (x) {
+  case 0:// OK
+  case __builtin_is_constant_evaluated():// expected-note {{previous case}}
+  case std::is_constant_evaluated() + __builtin_is_constant_evaluated(): // expected-note {{previous case}}
+  case 1:// expected-error {{duplicate case value '1'}}
+  case 2:// expected-error {{duplicate case value '2'}}
+break;
+  }
+}
+
+constexpr size_t good_array_size() {
+  return std::is_constant_evaluated() ? 42 : static_cast(-1);
+}
+
+constexpr size_t bad_array_size() {
+  return std::is_constant_evaluated() ? static_cast(-1) : 13;
+}
+
+template 
+constexpr T require_constexpr(T v) {
+  if (!std::is_constant_evaluated())
+throw "BOOM";
+  return v;
+}
+
+void test_new_expr() {
+  constexpr size_t TooLarge = -1;
+  auto *x = new int[std::is_constant_evaluated() ? 1 : TooLarge];  // expected-error {{array is too large}}
+  auto *x2 = new int[std::is_constant_evaluated() ? TooLarge : 1]; // OK
+  auto *y = new int[1][std::is_constant_evaluated() ? TooLarge : 1]{}; // expected-error {{array is too large}}
+  auto *y2 = new int[1][require_constexpr(42)];
+}
+
+void test_alignas_operand() {
+  alignas(std::is_constant_evaluated() ? 8 : 2) char dummy;
+  static_assert(__alignof(dummy) == 8);
+}
+
+void test_static_assert_operand() {
+  static_assert(std::is_constant_evaluated(), "");
+}
+
+void test_enumerator() {
+  enum MyEnum {
+ZERO = 0,
+ONE = std::is_constant_evaluated()
+  };
+  static_assert(ONE == 1, "");
+}
+
+struct TestBitfieldWidth {
+  unsigned Bits : std::is_constant_evaluated();
+};
+
+void test_operand_of_noexcept_fn() noexcept(std::is_constant_evaluated());
+static_assert(noexcept(test_operand_of_noexcept_fn()), "");
+
+
+namespace test_ref_initialization {
+int x;
+int y;
+int  = __builtin_is_constant_evaluated() ? x : y;
+static_assert( == );
+
+} // namespace test_ref_initialization
+
+#if defined(__cpp_conditional_explicit)
+struct TestConditionalExplicit {
+  explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
+};
+TestConditionalExplicit e = 42;
+#endif
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -314,3 +314,9 @@
   memcpy(buf, src, 11); // expected-warning{{'memcpy' will always overflow; destination buffer has size 10, but size argument is 

[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-04-22 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith accepted this revision.
rsmith added a comment.
This revision is now accepted and ready to land.
Herald added a subscriber: dexonsmith.

LGTM, thanks!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-23 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 183248.
EricWF marked 2 inline comments as done.
EricWF added a comment.

- Add or correct tests as requested.
- Fix code gen for initializers of reference types to correctly evaluate the 
initializer as a constant expression.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500

Files:
  include/clang/Basic/Builtins.def
  lib/AST/ExprConstant.cpp
  lib/Basic/Builtins.cpp
  lib/CodeGen/CGDecl.cpp
  test/CodeGenCXX/builtin-is-constant-evaluated.cpp
  test/Sema/builtins.c
  test/SemaCXX/builtin-is-constant-evaluated.cpp

Index: test/SemaCXX/builtin-is-constant-evaluated.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-is-constant-evaluated.cpp
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+using size_t = decltype(sizeof(int));
+
+namespace std {
+inline constexpr bool is_constant_evaluated() noexcept {
+  return __builtin_is_constant_evaluated();
+}
+} // namespace std
+
+extern int dummy; // expected-note 1+ {{declared here}}
+
+static_assert(__builtin_is_constant_evaluated());
+static_assert(noexcept(__builtin_is_constant_evaluated()));
+
+constexpr bool b = __builtin_is_constant_evaluated();
+static_assert(b);
+
+const int n = __builtin_is_constant_evaluated() ? 4 : dummy;
+static_assert(n == 4);
+constexpr int cn = __builtin_is_constant_evaluated() ? 11 : dummy;
+static_assert(cn == 11);
+// expected-error@+1 {{'bn' must be initialized by a constant expression}}
+constexpr int bn = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{non-const variable 'dummy' is not allowed}}
+
+const int n2 = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{declared here}}
+static_assert(n2 == 42);   // expected-error {{static_assert expression is not an integral constant}}
+// expected-note@-1 {{initializer of 'n2' is not a constant expression}}
+
+template 
+struct Templ { static_assert(V); static_assert(Default); };
+Templ<__builtin_is_constant_evaluated()> x; // type X
+
+template 
+void test_if_constexpr() {
+  if constexpr (__builtin_is_constant_evaluated()) {
+static_assert(__is_same(T, int));
+  } else {
+using Test = typename T::DOES_NOT_EXIST;
+  }
+}
+template void test_if_constexpr();
+
+void test_array_decl() {
+  char x[__builtin_is_constant_evaluated() + std::is_constant_evaluated()];
+  static_assert(sizeof(x) == 2, "");
+}
+
+void test_case_stmt(int x) {
+  switch (x) {
+  case 0:// OK
+  case __builtin_is_constant_evaluated():// expected-note {{previous case}}
+  case std::is_constant_evaluated() + __builtin_is_constant_evaluated(): // expected-note {{previous case}}
+  case 1:// expected-error {{duplicate case value '1'}}
+  case 2:// expected-error {{duplicate case value '2'}}
+break;
+  }
+}
+
+constexpr size_t good_array_size() {
+  return std::is_constant_evaluated() ? 42 : static_cast(-1);
+}
+
+constexpr size_t bad_array_size() {
+  return std::is_constant_evaluated() ? static_cast(-1) : 13;
+}
+
+template 
+constexpr T require_constexpr(T v) {
+  if (!std::is_constant_evaluated())
+throw "BOOM";
+  return v;
+}
+
+void test_new_expr() {
+  constexpr size_t TooLarge = -1;
+  auto *x = new int[std::is_constant_evaluated() ? 1 : TooLarge];  // expected-error {{array is too large}}
+  auto *x2 = new int[std::is_constant_evaluated() ? TooLarge : 1]; // OK
+  auto *y = new int[1][std::is_constant_evaluated() ? TooLarge : 1]{}; // expected-error {{array is too large}}
+  auto *y2 = new int[1][require_constexpr(42)];
+}
+
+void test_alignas_operand() {
+  alignas(std::is_constant_evaluated() ? 8 : 2) char dummy;
+  static_assert(__alignof(dummy) == 8);
+}
+
+void test_static_assert_operand() {
+  static_assert(std::is_constant_evaluated(), "");
+}
+
+void test_enumerator() {
+  enum MyEnum {
+ZERO = 0,
+ONE = std::is_constant_evaluated()
+  };
+  static_assert(ONE == 1, "");
+}
+
+struct TestBitfieldWidth {
+  unsigned Bits : std::is_constant_evaluated();
+};
+
+void test_operand_of_noexcept_fn() noexcept(std::is_constant_evaluated());
+static_assert(noexcept(test_operand_of_noexcept_fn()), "");
+
+
+namespace test_ref_initialization {
+int x;
+int y;
+int  = __builtin_is_constant_evaluated() ? x : y;
+static_assert( == );
+
+} // namespace test_ref_initialization
+
+#if defined(__cpp_conditional_explicit)
+struct TestConditionalExplicit {
+  explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
+};
+TestConditionalExplicit e = 42;
+#endif
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c

[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-23 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 6 inline comments as done.
EricWF added inline comments.



Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:41-42
+
+// CHECK-STATIC-DAG: @p = global i32 26,
+CONSTINIT int p = f(); // f().m == 13; initialized to 26
+

rsmith wrote:
> Do we get the same result without the attribute?
Yes it does. But Ill ad a second test to verify. 



Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:73
+  // CHECK-ARR: %x1 = alloca [101 x i8],
+  char x1[std::is_constant_evaluated() || __builtin_is_constant_evaluated() ? 
101 : 1];
+

rsmith wrote:
> Why call both the std:: function and the builtin here? If we want to test 
> that both work, shouldn't we use `&&` instead of `||`?
I think I was trying to ensure `std::is_constant_evaluated` worked the same as 
calling the builtin directly.
Using `||` here was a mistake. Fixed.



Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:91
+bool test_constant_initialized_local(int k) {
+  // CHECK-FOLD: store i8 0, i8* %n,
+  // CHECK-FOLD: store volatile i8* %n, i8** %p,

rsmith wrote:
> This is incorrect: `n` should be initialized to `true` because it occurs in 
> the initializer of a variable that is usable in constant expressions.
Ack.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-23 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

Thanks for the added tests! They seem to have found a bug in the handling of 
local const integral variables.




Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:41-42
+
+// CHECK-STATIC-DAG: @p = global i32 26,
+CONSTINIT int p = f(); // f().m == 13; initialized to 26
+

Do we get the same result without the attribute?



Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:73
+  // CHECK-ARR: %x1 = alloca [101 x i8],
+  char x1[std::is_constant_evaluated() || __builtin_is_constant_evaluated() ? 
101 : 1];
+

Why call both the std:: function and the builtin here? If we want to test that 
both work, shouldn't we use `&&` instead of `||`?



Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:91
+bool test_constant_initialized_local(int k) {
+  // CHECK-FOLD: store i8 0, i8* %n,
+  // CHECK-FOLD: store volatile i8* %n, i8** %p,

This is incorrect: `n` should be initialized to `true` because it occurs in the 
initializer of a variable that is usable in constant expressions.



Comment at: test/CodeGenCXX/builtin-is-constant-evaluated.cpp:122
+  // CHECK-FOLD: store i32* %i_non_constant, i32** %r,
+  const int  = __builtin_is_constant_evaluated() ? i_constant : 
i_non_constant;
+}

Can you also test the case where an automatic storage duration reference is 
initialized to one of two static storage duration variables? In that case, we 
should pick the 'constant' case because the initializer would be a constant 
expression.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-15 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 181974.
EricWF added a comment.

Add the requested tests.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500

Files:
  include/clang/Basic/Builtins.def
  lib/AST/ExprConstant.cpp
  lib/Basic/Builtins.cpp
  test/CodeGenCXX/builtin-is-constant-evaluated.cpp
  test/Sema/builtins.c
  test/SemaCXX/builtin-is-constant-evaluated.cpp

Index: test/SemaCXX/builtin-is-constant-evaluated.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-is-constant-evaluated.cpp
@@ -0,0 +1,121 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+using size_t = decltype(sizeof(int));
+
+namespace std {
+inline constexpr bool is_constant_evaluated() noexcept {
+  return __builtin_is_constant_evaluated();
+}
+} // namespace std
+
+extern int dummy; // expected-note 1+ {{declared here}}
+
+static_assert(__builtin_is_constant_evaluated());
+static_assert(noexcept(__builtin_is_constant_evaluated()));
+
+constexpr bool b = __builtin_is_constant_evaluated();
+static_assert(b);
+
+const int n = __builtin_is_constant_evaluated() ? 4 : dummy;
+static_assert(n == 4);
+constexpr int cn = __builtin_is_constant_evaluated() ? 11 : dummy;
+static_assert(cn == 11);
+// expected-error@+1 {{'bn' must be initialized by a constant expression}}
+constexpr int bn = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{non-const variable 'dummy' is not allowed}}
+
+const int n2 = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{declared here}}
+static_assert(n2 == 42);   // expected-error {{static_assert expression is not an integral constant}}
+// expected-note@-1 {{initializer of 'n2' is not a constant expression}}
+
+template 
+struct Templ { static_assert(V); static_assert(Default); };
+Templ<__builtin_is_constant_evaluated()> x; // type X
+
+template 
+void test_if_constexpr() {
+  if constexpr (__builtin_is_constant_evaluated()) {
+static_assert(__is_same(T, int));
+  } else {
+using Test = typename T::DOES_NOT_EXIST;
+  }
+}
+template void test_if_constexpr();
+
+void test_array_decl() {
+  char x[__builtin_is_constant_evaluated() + std::is_constant_evaluated()];
+  static_assert(sizeof(x) == 2, "");
+}
+
+void test_case_stmt(int x) {
+  switch (x) {
+  case 0:// OK
+  case __builtin_is_constant_evaluated():// expected-note {{previous case}}
+  case std::is_constant_evaluated() + __builtin_is_constant_evaluated(): // expected-note {{previous case}}
+  case 1:// expected-error {{duplicate case value '1'}}
+  case 2:// expected-error {{duplicate case value '2'}}
+break;
+  }
+}
+
+constexpr size_t good_array_size() {
+  return std::is_constant_evaluated() ? 42 : static_cast(-1);
+}
+
+constexpr size_t bad_array_size() {
+  return std::is_constant_evaluated() ? static_cast(-1) : 13;
+}
+
+template 
+constexpr T require_constexpr(T v) {
+  if (!std::is_constant_evaluated())
+throw "BOOM";
+  return v;
+}
+
+void test_new_expr() {
+  constexpr size_t TooLarge = -1;
+  auto *x = new int[std::is_constant_evaluated() ? 1 : TooLarge];  // expected-error {{array is too large}}
+  auto *x2 = new int[std::is_constant_evaluated() ? TooLarge : 1]; // OK
+  auto *y = new int[1][std::is_constant_evaluated() ? TooLarge : 1]{}; // expected-error {{array is too large}}
+  auto *y2 = new int[1][require_constexpr(42)];
+}
+
+void test_alignas_operand() {
+  alignas(std::is_constant_evaluated() ? 8 : 2) char dummy;
+  static_assert(__alignof(dummy) == 8);
+}
+
+void test_static_assert_operand() {
+  static_assert(std::is_constant_evaluated(), "");
+}
+
+void test_enumerator() {
+  enum MyEnum {
+ZERO = 0,
+ONE = std::is_constant_evaluated()
+  };
+  static_assert(ONE == 1, "");
+}
+
+struct TestBitfieldWidth {
+  unsigned Bits : std::is_constant_evaluated();
+};
+
+void test_operand_of_noexcept_fn() noexcept(std::is_constant_evaluated());
+static_assert(noexcept(test_operand_of_noexcept_fn()), "");
+
+
+namespace test_ref_initialization {
+int x;
+int y;
+int  = __builtin_is_constant_evaluated() ? x : y;
+static_assert( == );
+
+} // namespace test_ref_initialization
+
+#if defined(__cpp_conditional_explicit)
+struct TestConditionalExplicit {
+  explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
+};
+TestConditionalExplicit e = 42;
+#endif
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -314,3 +314,9 @@
   memcpy(buf, src, 11); // expected-warning{{'memcpy' will always overflow; destination buffer has size 10, but size argument is 11}}
   

[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-11 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

In D55500#1347493 , @EricWF wrote:

> @rsmith, what sorts of additional tests are needed?


Let's see...

- test that we use the constant initializer for suitably-constant-initialized 
locals even if we can't constant-fold the reference to them:

  bool f(int k) {
const bool n = is_constant_evaluated();
const bool *volatile p = n;
return *p;
  }



- test that we suitably handle local references initialized by constant 
expressions (and local `constexpr` variables), and non-`const` globals
- test that `__builtin_is_constant_evaluated()` returns false in contexts that 
IR generation might constant-fold (eg, the operand of a non-`constexpr` `if` or 
the left-hand side of a `?:` expression)
- ensure that the right value is returned in all the cases that are 
syntactically //constant-expression//s in the C++ grammar:
  - second or subsequent array bound in a //new-expression//
  - `case` labels
  - operand of `static_assert`
  - array bounds (but be careful around the treatment of VLAs! for them we want 
the "try evaluating it as a constant expression and fall back to treating it as 
a non-constant expression" rule that we have for the initializers of globals)
  - values of enumerators
  - operand of `alignas`
  - width of a bit-field
  - template arguments (but bizarrely not default template arguments! I think 
that's a bug and I'll bring it up on the core reflector.)
  - operand of `noexcept` (and eventually `explicit` -- please write a test for 
the latter with a FIXME to update the expectations, so we don't forget)




Comment at: include/clang/Basic/Builtins.def:758
 
+// Random C++ builtins.
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "ncu", CXX_LANG)

This should be grouped with `__builtin_launder`, though maybe moving that one 
here makes more sense than grouping them both under "GCC builtins" since 
they're directly implementing C++ stdlib functions.



Comment at: include/clang/Basic/Builtins.def:759
+// Random C++ builtins.
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "ncu", CXX_LANG)
+

bruno wrote:
> EricWF wrote:
> > EricWF wrote:
> > > bruno wrote:
> > > > Name bikeshedding : perhaps the builtin name could be detached from the 
> > > > std:: name? Suggestion: `__builtin_in_constant_evaluation_context`
> > > I'm not sure detaching it from the `std::` name is desirable. Most 
> > > importantly it should match w/e GCC does/decides to do.
> > > 
> > > But if it is, we should name in deference to the standardese it 
> > > implements. Specifically weither an expression or conversion is 
> > > //manifestly constant-evaluated// 
> > > [[expr.const](http://eel.is/c++draft/expr.const#11)]p11.
> > > 
> > > Therefore I proffer  `__builtin_is_manifestly_constant_evaluated()` or 
> > > `__builtin_is_being_manifestly_constant_evaluated()`.
> > > 
> > > 
> > Actually, GCC has `__builtin_is_constant_evaluated` so we should use that 
> > name too.
> Agreed!
I don't think the "u" flag has any meaning here (there are no arguments, so no 
unevaluated arguments), and it would reduce the complexity of this declaration 
if you remove it.

I don't think the "c" flag is formally correct -- a program can contain two 
calls to `__builtin_is_constant_evaluated()` that return different values (even 
"U" appears to be incorrect). It would, for example, be reasonable for Clang to 
warn on:

```
const bool b = pure_fn();
return b == pure_fn();
```

... on the basis that the comparison must always evaluate to `true`. But such a 
warning would be incorrect for `__builtin_is_constant_evaluated`, so it's not a 
pure function.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-07 Thread Bruno Cardoso Lopes via Phabricator via cfe-commits
bruno added inline comments.



Comment at: include/clang/Basic/Builtins.def:759
+// Random C++ builtins.
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "ncu", CXX_LANG)
+

EricWF wrote:
> EricWF wrote:
> > bruno wrote:
> > > Name bikeshedding : perhaps the builtin name could be detached from the 
> > > std:: name? Suggestion: `__builtin_in_constant_evaluation_context`
> > I'm not sure detaching it from the `std::` name is desirable. Most 
> > importantly it should match w/e GCC does/decides to do.
> > 
> > But if it is, we should name in deference to the standardese it implements. 
> > Specifically weither an expression or conversion is //manifestly 
> > constant-evaluated// 
> > [[expr.const](http://eel.is/c++draft/expr.const#11)]p11.
> > 
> > Therefore I proffer  `__builtin_is_manifestly_constant_evaluated()` or 
> > `__builtin_is_being_manifestly_constant_evaluated()`.
> > 
> > 
> Actually, GCC has `__builtin_is_constant_evaluated` so we should use that 
> name too.
Agreed!


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2019-01-05 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked an inline comment as done.
EricWF added a comment.

Ping! I would like to land this before the next release.

@rsmith, what sorts of additional tests are needed?




Comment at: include/clang/Basic/Builtins.def:759
+// Random C++ builtins.
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "ncu", CXX_LANG)
+

EricWF wrote:
> bruno wrote:
> > Name bikeshedding : perhaps the builtin name could be detached from the 
> > std:: name? Suggestion: `__builtin_in_constant_evaluation_context`
> I'm not sure detaching it from the `std::` name is desirable. Most 
> importantly it should match w/e GCC does/decides to do.
> 
> But if it is, we should name in deference to the standardese it implements. 
> Specifically weither an expression or conversion is //manifestly 
> constant-evaluated// [[expr.const](http://eel.is/c++draft/expr.const#11)]p11.
> 
> Therefore I proffer  `__builtin_is_manifestly_constant_evaluated()` or 
> `__builtin_is_being_manifestly_constant_evaluated()`.
> 
> 
Actually, GCC has `__builtin_is_constant_evaluated` so we should use that name 
too.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2018-12-10 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 2 inline comments as done.
EricWF added a comment.

Sorry for the delayed response. My email filters were incorrect.




Comment at: include/clang/Basic/Builtins.def:759
+// Random C++ builtins.
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "ncu", CXX_LANG)
+

bruno wrote:
> Name bikeshedding : perhaps the builtin name could be detached from the std:: 
> name? Suggestion: `__builtin_in_constant_evaluation_context`
I'm not sure detaching it from the `std::` name is desirable. Most importantly 
it should match w/e GCC does/decides to do.

But if it is, we should name in deference to the standardese it implements. 
Specifically weither an expression or conversion is //manifestly 
constant-evaluated// [[expr.const](http://eel.is/c++draft/expr.const#11)]p11.

Therefore I proffer  `__builtin_is_manifestly_constant_evaluated()` or 
`__builtin_is_being_manifestly_constant_evaluated()`.





Comment at: lib/AST/ExprConstant.cpp:8207
 
+  case Builtin::BI__builtin_is_constant_evaluated:
+return Success(Info.InConstantContext, E);

bruno wrote:
> Do we need compat and extension warnings for the use of this builtin before 
> c++2a? I assume people will play with the builtin before the library facility 
> is there. OTOH, since this will be mainly exposed as a library thing, 
> whatever check for c++ version is done at the library level should be enough?
No. We don't  warn for any other builtin used to serve the standard library 
(`__is_constructible()`, `__builtin_addressof()`, etc)

The builtin is useful in all dialects, and I suspect users will frequently want 
to call it directly. If `__has_builtin(__builtin_is_constant_evaluated)` 
returns true, it should be safe to use.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2018-12-10 Thread Bruno Cardoso Lopes via Phabricator via cfe-commits
bruno added a comment.

Hi Eric,

Thanks for working on this!




Comment at: include/clang/Basic/Builtins.def:759
+// Random C++ builtins.
+LANGBUILTIN(__builtin_is_constant_evaluated, "b", "ncu", CXX_LANG)
+

Name bikeshedding : perhaps the builtin name could be detached from the std:: 
name? Suggestion: `__builtin_in_constant_evaluation_context`



Comment at: lib/AST/ExprConstant.cpp:8207
 
+  case Builtin::BI__builtin_is_constant_evaluated:
+return Success(Info.InConstantContext, E);

Do we need compat and extension warnings for the use of this builtin before 
c++2a? I assume people will play with the builtin before the library facility 
is there. OTOH, since this will be mainly exposed as a library thing, whatever 
check for c++ version is done at the library level should be enough?


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55500/new/

https://reviews.llvm.org/D55500



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55500: [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

2018-12-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
EricWF added reviewers: rsmith, MaskRay, bruno, void.
Herald added a subscriber: kristina.

This patch implements `__builtin_is_constant_evaluated` as specifier by P0595R2 
. It is built on the back of Bill Wendling's work 
for `__builtin_constant_p()`.

More tests to come, but early feedback is appreciated.

I plan to implement warnings for common mis-usages like those belowe in a 
following patch:

  void foo(int x) {
if constexpr (std::is_constant_evaluated())) { // condition is always 
`true`. Should use plain `if` instead.
 foo_constexpr(x);
} else {
  foo_runtime(x);
}
  }




Repository:
  rC Clang

https://reviews.llvm.org/D55500

Files:
  include/clang/Basic/Builtins.def
  lib/AST/ExprConstant.cpp
  lib/Basic/Builtins.cpp
  test/CodeGenCXX/builtin-is-constant-evaluated.cpp
  test/Sema/builtins.c
  test/SemaCXX/builtin-is-constant-evaluated.cpp

Index: test/SemaCXX/builtin-is-constant-evaluated.cpp
===
--- /dev/null
+++ test/SemaCXX/builtin-is-constant-evaluated.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+using size_t = decltype(sizeof(int));
+
+namespace std {
+inline constexpr bool is_constant_evaluated() noexcept {
+  return __builtin_is_constant_evaluated();
+}
+} // namespace std
+
+extern int dummy; // expected-note 1+ {{declared here}}
+
+static_assert(__builtin_is_constant_evaluated());
+
+constexpr bool b = __builtin_is_constant_evaluated();
+static_assert(b);
+
+const int n = __builtin_is_constant_evaluated() ? 4 : dummy;
+static_assert(n == 4);
+constexpr int cn = __builtin_is_constant_evaluated() ? 11 : dummy;
+static_assert(cn == 11);
+// expected-error@+1 {{'bn' must be initialized by a constant expression}}
+constexpr int bn = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{non-const variable 'dummy' is not allowed}}
+
+
+const int n2 = __builtin_is_constant_evaluated() ? dummy : 42; // expected-note {{declared here}}
+static_assert(n2 == 42); // expected-error {{static_assert expression is not an integral constant}}
+// expected-note@-1 {{initializer of 'n2' is not a constant expression}}
+
+template struct Templ { static_assert(V);};
+Templ<__builtin_is_constant_evaluated()> x; // type X
+
+template 
+void test_if_constexpr() {
+  if constexpr (__builtin_is_constant_evaluated()) {
+static_assert(__is_same(T, int));
+  } else {
+using Test = typename T::DOES_NOT_EXIST;
+  }
+}
+template void test_if_constexpr();
+
+void test_array_decl() {
+  char x[__builtin_is_constant_evaluated() + std::is_constant_evaluated()];
+  static_assert(sizeof(x) == 2, "");
+}
+
+void test_case_stmt(int x) {
+  switch (x) {
+  case 0:// OK
+  case __builtin_is_constant_evaluated():// expected-note {{previous case}}
+  case std::is_constant_evaluated() + __builtin_is_constant_evaluated(): // expected-note {{previous case}}
+  case 1:// expected-error {{duplicate case value '1'}}
+  case 2:// expected-error {{duplicate case value '2'}}
+break;
+  }
+}
+
+constexpr size_t good_array_size() {
+  return std::is_constant_evaluated() ? 42 : static_cast(-1);
+}
+
+constexpr size_t bad_array_size() {
+  return std::is_constant_evaluated() ? static_cast(-1) : 13;
+}
+
+template 
+constexpr T require_constexpr(T v) {
+  if (!std::is_constant_evaluated())
+throw "BOOM";
+  return v;
+}
+
+void test_new_expr() {
+  constexpr size_t TooLarge = -1;
+  auto *x = new int[std::is_constant_evaluated() ? 1 : TooLarge];  // expected-error {{array is too large}}
+  auto *x2 = new int[std::is_constant_evaluated() ? TooLarge : 1]; // OK
+  auto *y = new int[1][std::is_constant_evaluated() ? TooLarge : 1]{}; // expected-error {{array is too large}}
+  auto *y2 = new int[1][require_constexpr(42)];
+}
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -296,3 +296,9 @@
   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}}
 }
+
+// Test that __builtin_is_constant_evaluated() is not allowed in C
+int test_cxx_builtin() {
+  // expected-error@+1 {{use of unknown builtin '__builtin_is_constant_evaluated'}}
+  return __builtin_is_constant_evaluated();
+}
Index: test/CodeGenCXX/builtin-is-constant-evaluated.cpp
===
--- /dev/null
+++ test/CodeGenCXX/builtin-is-constant-evaluated.cpp
@@