r359067 - [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed May 8 20:47:30 PDT 2019


I went ahead and did this in r360310.

On Thu, 25 Apr 2019 at 14:31, Richard Smith <richard at metafoo.co.uk> wrote:
>
> On Wed, 24 Apr 2019 at 19:28, Eric Fiselier via cfe-commits
> <cfe-commits at lists.llvm.org> wrote:
> > Do I just edit the HTML file directly?
> > Or is it generated by something?
>
> Just edit the HTML file directly.
>
> > On Wed, Apr 24, 2019 at 3:35 PM Richard Smith <richard at metafoo.co.uk> wrote:
> >>
> >> Thanks! Can you update cxx_status.html to mark P0595R2 as done?
> >>
> >> On Tue, 23 Apr 2019 at 19:21, Eric Fiselier via cfe-commits
> >> <cfe-commits at lists.llvm.org> wrote:
> >> >
> >> > Author: ericwf
> >> > Date: Tue Apr 23 19:23:30 2019
> >> > New Revision: 359067
> >> >
> >> > URL: http://llvm.org/viewvc/llvm-project?rev=359067&view=rev
> >> > Log:
> >> > [Builtins] Implement __builtin_is_constant_evaluated for use in C++2a
> >> >
> >> > Summary:
> >> > This patch implements `__builtin_is_constant_evaluated` as specifier by [P0595R2](https://wg21.link/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);
> >> >   }
> >> > }
> >> > ```
> >> >
> >> >
> >> >
> >> > Reviewers: rsmith, MaskRay, bruno, void
> >> >
> >> > Reviewed By: rsmith
> >> >
> >> > Subscribers: dexonsmith, zoecarver, fdeazeve, kristina, cfe-commits
> >> >
> >> > Differential Revision: https://reviews.llvm.org/D55500
> >> >
> >> > Added:
> >> >     cfe/trunk/test/CodeGenCXX/builtin-is-constant-evaluated.cpp
> >> >     cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp
> >> > Modified:
> >> >     cfe/trunk/include/clang/Basic/Builtins.def
> >> >     cfe/trunk/lib/AST/ExprConstant.cpp
> >> >     cfe/trunk/lib/Basic/Builtins.cpp
> >> >     cfe/trunk/lib/CodeGen/CGDecl.cpp
> >> >     cfe/trunk/test/Sema/builtins.c
> >> >
> >> > Modified: cfe/trunk/include/clang/Basic/Builtins.def
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=359067&r1=359066&r2=359067&view=diff
> >> > ==============================================================================
> >> > --- cfe/trunk/include/clang/Basic/Builtins.def (original)
> >> > +++ cfe/trunk/include/clang/Basic/Builtins.def Tue Apr 23 19:23:30 2019
> >> > @@ -500,6 +500,7 @@ BUILTIN(__builtin_vsprintf, "ic*cC*a", "
> >> >  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!
> >> >
> >> > Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=359067&r1=359066&r2=359067&view=diff
> >> > ==============================================================================
> >> > --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> >> > +++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Apr 23 19:23:30 2019
> >> > @@ -8279,6 +8279,9 @@ bool IntExprEvaluator::VisitBuiltinCallE
> >> >      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 @@ bool Expr::EvaluateAsConstantExpr(EvalRe
> >> >    EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
> >> >    EvalInfo Info(Ctx, Result, EM);
> >> >    Info.InConstantContext = true;
> >> > +
> >> >    if (!::Evaluate(Result.Val, Info, this))
> >> >      return false;
> >> >
> >> >
> >> > Modified: cfe/trunk/lib/Basic/Builtins.cpp
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Builtins.cpp?rev=359067&r1=359066&r2=359067&view=diff
> >> > ==============================================================================
> >> > --- cfe/trunk/lib/Basic/Builtins.cpp (original)
> >> > +++ cfe/trunk/lib/Basic/Builtins.cpp Tue Apr 23 19:23:30 2019
> >> > @@ -75,9 +75,12 @@ bool Builtin::Context::builtinIsSupporte
> >> >    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
> >> >
> >> > Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=359067&r1=359066&r2=359067&view=diff
> >> > ==============================================================================
> >> > --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
> >> > +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Apr 23 19:23:30 2019
> >> > @@ -1783,7 +1783,8 @@ void CodeGenFunction::EmitAutoVarInit(co
> >> >    }
> >> >
> >> >    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 !=
> >> >
> >> > Added: cfe/trunk/test/CodeGenCXX/builtin-is-constant-evaluated.cpp
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/builtin-is-constant-evaluated.cpp?rev=359067&view=auto
> >> > ==============================================================================
> >> > --- cfe/trunk/test/CodeGenCXX/builtin-is-constant-evaluated.cpp (added)
> >> > +++ cfe/trunk/test/CodeGenCXX/builtin-is-constant-evaluated.cpp Tue Apr 23 19:23:30 2019
> >> > @@ -0,0 +1,133 @@
> >> > +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -std=c++2a -o %t.ll
> >> > +// RUN: FileCheck -check-prefix=CHECK-FN-CG -input-file=%t.ll %s
> >> > +// RUN: FileCheck -check-prefix=CHECK-STATIC -input-file=%t.ll %s
> >> > +// RUN: FileCheck -check-prefix=CHECK-DYN -input-file=%t.ll %s
> >> > +// RUN: FileCheck -check-prefix=CHECK-ARR -input-file=%t.ll %s
> >> > +// RUN: FileCheck -check-prefix=CHECK-FOLD -input-file=%t.ll %s
> >> > +
> >> > +using size_t = decltype(sizeof(int));
> >> > +
> >> > +#define CONSTINIT __attribute__((require_constant_initialization))
> >> > +
> >> > +extern "C" [[noreturn]] void BOOM();
> >> > +extern "C" void OK();
> >> > +extern "C" size_t RANDU();
> >> > +
> >> > +namespace std {
> >> > +inline constexpr bool is_constant_evaluated() noexcept {
> >> > +  return __builtin_is_constant_evaluated();
> >> > +}
> >> > +} // namespace std
> >> > +
> >> > +// CHECK-FN-CG-LABEL: define zeroext i1 @_Z3foov()
> >> > +// CHECK-FN-CG: ret i1 false
> >> > +bool foo() {
> >> > +  return __builtin_is_constant_evaluated();
> >> > +}
> >> > +
> >> > +// CHECK-FN-CG-LABEL: define linkonce_odr i32 @_Z1fv()
> >> > +constexpr int f() {
> >> > +  // CHECK-FN-CG: store i32 13, i32* %n, align 4
> >> > +  // CHECK-FN-CG: store i32 17, i32* %m, align 4
> >> > +  // CHECK-FN-CG:  %1 = load i32, i32* %m, align 4
> >> > +  // CHECK-FN-CG: %add = add nsw i32 %1, 13
> >> > +  // CHECK-FN-CG: ret i32 %add
> >> > +  const int n = __builtin_is_constant_evaluated() && std::is_constant_evaluated() ? 13 : 17; // n == 13
> >> > +  int m = __builtin_is_constant_evaluated() ? 13 : 17;       // m might be 13 or 17 (see below)
> >> > +  char arr[n] = {};                                          // char[13]
> >> > +  return m + int(sizeof(arr));
> >> > +}
> >> > +
> >> > +// CHECK-STATIC-DAG: @p = global i32 26,
> >> > +CONSTINIT int p = f(); // f().m == 13; initialized to 26
> >> > +// CHECK-STATIC-DAG: @p2 = global i32 26,
> >> > +int p2 = f(); // same result without CONSTINIT
> >> > +
> >> > +// CHECK-DYN-LABEL: define internal void @__cxx_global_var_init()
> >> > +// CHECK-DYN: %0 = load i32, i32* @p, align 4
> >> > +// CHECK-DYN-NEXT: %call = call i32 @_Z1fv()
> >> > +// CHECK-DYN-NEXT: %add = add nsw i32 %0, %call
> >> > +// CHECK-DYN-NEXT: store i32 %add, i32* @q, align 4
> >> > +// CHECK-DYN-NEXT: ret void
> >> > +int q = p + f(); // m == 17 for this call; initialized to 56
> >> > +
> >> > +int y;
> >> > +
> >> > +// CHECK-STATIC-DAG: @b = global i32 2,
> >> > +CONSTINIT int b = __builtin_is_constant_evaluated() ? 2 : y; // static initialization to 2
> >> > +
> >> > +// CHECK-DYN-LABEL: define internal void @__cxx_global_var_init.1()
> >> > +// CHECK-DYN: %0 = load i32, i32* @y, align 4
> >> > +// CHECK-DYN: %1 = load i32, i32* @y, align 4
> >> > +// CHECK-DYN-NEXT: %add = add
> >> > +// CHECK-DYN-NEXT: store i32 %add, i32* @c,
> >> > +int c = y + (__builtin_is_constant_evaluated() ? 2 : y); // dynamic initialization to y+y
> >> > +
> >> > +// CHECK-DYN-LABEL: define internal void @__cxx_global_var_init.2()
> >> > +// CHECK-DYN: store i32 1, i32* @_ZL1a, align 4
> >> > +// CHECK-DYN-NEXT: ret void
> >> > +const int a = __builtin_is_constant_evaluated() ? y : 1; // dynamic initialization to 1
> >> > +const int *a_sink = &a;
> >> > +
> >> > +// CHECK-ARR-LABEL: define void @_Z13test_arr_exprv
> >> > +void test_arr_expr() {
> >> > +  // CHECK-ARR: %x1 = alloca [101 x i8],
> >> > +  char x1[std::is_constant_evaluated() && __builtin_is_constant_evaluated() ? 101 : 1];
> >> > +
> >> > +  // CHECK-ARR: %x2 = alloca [42 x i8],
> >> > +  char x2[std::is_constant_evaluated() && __builtin_is_constant_evaluated() ? 42 : RANDU()];
> >> > +
> >> > +  // CHECK-ARR: call i8* @llvm.stacksave()
> >> > +  // CHECK-ARR: %vla = alloca i8, i64 13,
> >> > +  char x3[std::is_constant_evaluated() || __builtin_is_constant_evaluated() ? RANDU() : 13];
> >> > +}
> >> > +
> >> > +// CHECK-ARR-LABEL: define void @_Z17test_new_arr_exprv
> >> > +void test_new_arr_expr() {
> >> > +  // CHECK-ARR: call i8* @_Znam(i64 17)
> >> > +  new char[std::is_constant_evaluated() || __builtin_is_constant_evaluated() ? 1 : 17];
> >> > +}
> >> > +
> >> > +// CHECK-FOLD-LABEL: @_Z31test_constant_initialized_locali(
> >> > +bool test_constant_initialized_local(int k) {
> >> > +  // CHECK-FOLD: store i8 1, i8* %n,
> >> > +  // CHECK-FOLD: store volatile i8* %n, i8** %p,
> >> > +  const bool n = __builtin_is_constant_evaluated() && std::is_constant_evaluated();
> >> > +  const bool *volatile p = &n;
> >> > +  return *p;
> >> > +}
> >> > +
> >> > +// CHECK-FOLD-LABEL: define void @_Z21test_ir_constant_foldv()
> >> > +void test_ir_constant_fold() {
> >> > +  // CHECK-FOLD-NEXT: entry:
> >> > +  // CHECK-FOLD-NEXT: call void @OK()
> >> > +  // CHECK-FOLD-NEXT: call void @OK()
> >> > +  // CHECK-FOLD-NEXT: ret void
> >> > +  if (std::is_constant_evaluated()) {
> >> > +    BOOM();
> >> > +  } else {
> >> > +    OK();
> >> > +  }
> >> > +  std::is_constant_evaluated() ? BOOM() : OK();
> >> > +}
> >> > +
> >> > +// CHECK-STATIC-DAG: @ir = constant i32* @i_constant,
> >> > +int i_constant;
> >> > +int i_not_constant;
> >> > +int &ir = __builtin_is_constant_evaluated() ? i_constant : i_not_constant;
> >> > +
> >> > +// CHECK-FOLD-LABEL: @_Z35test_ref_initialization_local_scopev()
> >> > +void test_ref_initialization_local_scope() {
> >> > +  const int i_constant = 42;
> >> > +  const int i_non_constant = 101;
> >> > +  // CHECK-FOLD: store i32* %i_non_constant, i32** %r,
> >> > +  const int &r = __builtin_is_constant_evaluated() ? i_constant : i_non_constant;
> >> > +}
> >> > +
> >> > +// CHECK-FOLD-LABEL: @_Z22test_ref_to_static_varv()
> >> > +void test_ref_to_static_var() {
> >> > +  static int i_constant = 42;
> >> > +  static int i_non_constant = 101;
> >> > +  // CHECK-FOLD: store i32* @_ZZ22test_ref_to_static_varvE10i_constant, i32** %r,
> >> > +  int &r = __builtin_is_constant_evaluated() ? i_constant : i_non_constant;
> >> > +}
> >> > \ No newline at end of file
> >> >
> >> > Modified: cfe/trunk/test/Sema/builtins.c
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/builtins.c?rev=359067&r1=359066&r2=359067&view=diff
> >> > ==============================================================================
> >> > --- cfe/trunk/test/Sema/builtins.c (original)
> >> > +++ cfe/trunk/test/Sema/builtins.c Tue Apr 23 19:23:30 2019
> >> > @@ -314,3 +314,9 @@ void test23() {
> >> >    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{{'memcpy' 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 at +1 {{use of unknown builtin '__builtin_is_constant_evaluated'}}
> >> > +  return __builtin_is_constant_evaluated();
> >> > +}
> >> >
> >> > Added: cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp
> >> > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp?rev=359067&view=auto
> >> > ==============================================================================
> >> > --- cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp (added)
> >> > +++ cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp Tue Apr 23 19:23:30 2019
> >> > @@ -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 at +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 at -1 {{initializer of 'n2' is not a constant expression}}
> >> > +
> >> > +template <bool V, bool Default = std::is_constant_evaluated()>
> >> > +struct Templ { static_assert(V); static_assert(Default); };
> >> > +Templ<__builtin_is_constant_evaluated()> x; // type X<true>
> >> > +
> >> > +template <class T>
> >> > +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<int>();
> >> > +
> >> > +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<size_t>(-1);
> >> > +}
> >> > +
> >> > +constexpr size_t bad_array_size() {
> >> > +  return std::is_constant_evaluated() ? static_cast<size_t>(-1) : 13;
> >> > +}
> >> > +
> >> > +template <class T>
> >> > +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 &r = __builtin_is_constant_evaluated() ? x : y;
> >> > +static_assert(&r == &x);
> >> > +
> >> > +} // namespace test_ref_initialization
> >> > +
> >> > +#if defined(__cpp_conditional_explicit)
> >> > +struct TestConditionalExplicit {
> >> > +  explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
> >> > +};
> >> > +TestConditionalExplicit e = 42;
> >> > +#endif
> >> >
> >> >
> >> > _______________________________________________
> >> > cfe-commits mailing list
> >> > cfe-commits at lists.llvm.org
> >> > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
> >
> > _______________________________________________
> > cfe-commits mailing list
> > cfe-commits at lists.llvm.org
> > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list