[PATCH] D40218: [Clang] Add __builtin_launder

2018-12-14 Thread Eric Fiselier via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC349195: [Clang] Add __builtin_launder (authored by EricWF, 
committed by ).

Repository:
  rC Clang

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

https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,95 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp, int ()[5]) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(Arr);
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+void test_launder_return_type(const int ()[101], int ()[42][13],
+  void (**)()) {
+  TEST_TYPE(ArrayRef, const int *);
+  TEST_TYPE(MArrRef, int(*)[13]);
+  TEST_TYPE(FuncPtrRef, void (**)());
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  static_assert(test_in_constexpr(i), "");
+}
+
+struct Incomplete; // expected-note {{forward declaration}}
+struct IncompleteMember {
+  Incomplete 
+};
+void test_incomplete(Incomplete *i, IncompleteMember *im) {
+  // expected-error@+1 {{incomplete type 'test_launder::Incomplete' where a complete type is required}}
+  __builtin_launder(i);
+  __builtin_launder(); // OK
+  __builtin_launder(im); // OK
+}
+
+void test_noexcept(int *i) {
+  static_assert(noexcept(__builtin_launder(i)), "");
+}
+#undef TEST_TYPE
+} // end namespace test_launder
Index: test/CodeGen/builtins.c
===
--- test/CodeGen/builtins.c
+++ test/CodeGen/builtins.c
@@ -132,6 +132,8 @@
   R(extract_return_addr, ());
   P(signbit, (1.0));
 
+  R(launder, ());
+
   return 0;
 }
 
@@ -396,6 +398,15 @@
   return __builtin_readcyclecounter();
 }
 
+/// __builtin_launder should be a NOP in C since there are no 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-12-14 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 178267.
EricWF added a comment.

Merging with upstream. Preparing to commit.


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

https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,95 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp, int ()[5]) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(Arr);
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+void test_launder_return_type(const int ()[101], int ()[42][13],
+  void (**)()) {
+  TEST_TYPE(ArrayRef, const int *);
+  TEST_TYPE(MArrRef, int(*)[13]);
+  TEST_TYPE(FuncPtrRef, void (**)());
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  static_assert(test_in_constexpr(i), "");
+}
+
+struct Incomplete; // expected-note {{forward declaration}}
+struct IncompleteMember {
+  Incomplete 
+};
+void test_incomplete(Incomplete *i, IncompleteMember *im) {
+  // expected-error@+1 {{incomplete type 'test_launder::Incomplete' where a complete type is required}}
+  __builtin_launder(i);
+  __builtin_launder(); // OK
+  __builtin_launder(im); // OK
+}
+
+void test_noexcept(int *i) {
+  static_assert(noexcept(__builtin_launder(i)), "");
+}
+#undef TEST_TYPE
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -258,6 +258,24 @@
 return buf;
 }
 
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-12-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 177445.
EricWF marked 6 inline comments as done.
EricWF added a comment.

Address review comments.

@rsmith I think this is good to go. Just need your input on one change.


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

https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,95 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp, int ()[5]) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(Arr);
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+void test_launder_return_type(const int ()[101], int ()[42][13],
+  void (**)()) {
+  TEST_TYPE(ArrayRef, const int *);
+  TEST_TYPE(MArrRef, int(*)[13]);
+  TEST_TYPE(FuncPtrRef, void (**)());
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  static_assert(test_in_constexpr(i), "");
+}
+
+struct Incomplete; // expected-note {{forward declaration}}
+struct IncompleteMember {
+  Incomplete 
+};
+void test_incomplete(Incomplete *i, IncompleteMember *im) {
+  // expected-error@+1 {{incomplete type 'test_launder::Incomplete' where a complete type is required}}
+  __builtin_launder(i);
+  __builtin_launder(); // OK
+  __builtin_launder(im); // OK
+}
+
+void test_noexcept(int *i) {
+  static_assert(noexcept(__builtin_launder(i)), "");
+}
+#undef TEST_TYPE
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -258,6 +258,24 @@
 return buf;
 }
 
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-12-09 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 22 inline comments as done.
EricWF added inline comments.



Comment at: lib/CodeGen/CGBuiltin.cpp:1425-1426
+
+  // FIXME: We either have an incomplete class type, or we have a class 
template
+  // whose instantiation has not been forced. Example:
+  //

rsmith wrote:
> I think it's a bug that `launder` doesn't require `T` to be a complete type. 
> Can you file an LWG issue?
> 
> We should also decide whether we want to proactively fix this issue (require 
> the type to be complete from the `Sema` checking of the builtin and assert 
> that it's defined here) or not.
Apparently I misread the specification. The blanket wording in 
[[res.on.functions](http://eel.is/c++draft/res.on.functions#2.5)]  already 
prohibits this.

Though it's worth noting that GCC doesn't enforce this requirement (nor the one 
about function pointers).



Comment at: lib/CodeGen/CGBuiltin.cpp:1451
+return false;
+  llvm::DenseSet Seen;
+  return TypeRequiresBuiltinLaunderImp(CGM.getContext(), Ty, Seen);

rsmith wrote:
> Would `SmallPtrSet` be a better choice here?
I have no idea. I'm ignorant to the internals of both containers. Since you 
asked the question I'll assume it is and make the change.
If you would like, I can do further investigation upon request.



Comment at: lib/Sema/SemaChecking.cpp:885-887
+  // Don't perform LValue conversions since they may strip things like the
+  // restrict qualifier
+  ExprResult Arg = S.DefaultFunctionArrayConversion(OrigArg);

rsmith wrote:
> Instead of performing some of the conversions here and some of them as part 
> of initialization, I think it'd be more obvious to compute the builtin's 
> parameter type here (which is the type of the argument if it's not of array 
> [or function] type, and the decayed type of the argument otherwise), and do 
> the decay and lvalue-to-rvalue conversion as part of the parameter 
> initialization below.
> 
> The current code arrangement (and especially this comment) leaves a reader 
> thinking "but you *need* an lvalue-to-rvalue conversion if the argument is an 
> lvalue".
Ack.

I think I've implemented what you requested. Could you please verify?



Comment at: lib/Sema/SemaChecking.cpp:935
   return true;
+
 }

rsmith wrote:
> Did you mean to add this blank line?
Oh Richard, you're too kind. Of course I didn't mean to do that.



Comment at: test/CodeGen/builtins.c:404-409
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: store i32* [[TMP]], i32** %d

rsmith wrote:
> This test is not robust against minor IR differences such as variable or 
> basic block names changing (some of these change in a release build), and is 
> testing things that are not related to this builtin (eg, that we produce an 
> alloca for a function parameter and its relative order to an alloca for a 
> local variable).
> 
> I would remove everything here other than the load and the store, and add an 
> explicit check that we don't generate a launder call:
> 
> ```
>   // CHECK: [[TMP:%.*]] = load i32*,
>   // CHECK-NOT: @llvm.launder
>   // CHECK: store i32* [[TMP]],
> ```
If you're referring to the behavior of discarding value names, Clang CC1 only 
does that if `-discard-value-names` is explicitly passed, regardless of how the 
compiler is built, and so the names should be stable. (The Clang driver still 
conditionally passes `-discard-value-names` in release builds).

Are there other IR changes you have in mind?

None the less, I'll simply this test as requested. 



Comment at: test/CodeGenCXX/builtin-launder.cpp:16
+extern "C" void test_builtin_launder_virtual_fn(TestVirtualFn *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca [[TYPE:%.*]], align 8

rsmith wrote:
> This is likewise likely to fail with a release build of clang.
I just verified that they pass in both release and debug builds. I previously 
changed Clang and LLVM to make the label names consistent between the two 
configurations for the purposes of testing.

I'll still attempt to clean unnecessary checks up.



Comment at: test/SemaCXX/builtins.cpp:120
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");

rsmith wrote:
> `` doesn't what?
That's a great question. Not sure what I was up to when I wrote that. I tried a 
couple of things I though I might have been thinking, but they all passed.

Removing the comment.


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

https://reviews.llvm.org/D40218



___
cfe-commits mailing list
cfe-commits@lists.llvm.org

[PATCH] D40218: [Clang] Add __builtin_launder

2018-12-03 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/CodeGen/CGBuiltin.cpp:1425-1426
+
+  // FIXME: We either have an incomplete class type, or we have a class 
template
+  // whose instantiation has not been forced. Example:
+  //

I think it's a bug that `launder` doesn't require `T` to be a complete type. 
Can you file an LWG issue?

We should also decide whether we want to proactively fix this issue (require 
the type to be complete from the `Sema` checking of the builtin and assert that 
it's defined here) or not.



Comment at: lib/CodeGen/CGBuiltin.cpp:1437-1438
+
+  // if (!Seen.insert(Record).second)
+  //  return false;
+  for (FieldDecl *F : Record->fields()) {

Delete this commented-out code.



Comment at: lib/CodeGen/CGBuiltin.cpp:1451
+return false;
+  llvm::DenseSet Seen;
+  return TypeRequiresBuiltinLaunderImp(CGM.getContext(), Ty, Seen);

Would `SmallPtrSet` be a better choice here?



Comment at: lib/Sema/SemaChecking.cpp:885-887
+  // Don't perform LValue conversions since they may strip things like the
+  // restrict qualifier
+  ExprResult Arg = S.DefaultFunctionArrayConversion(OrigArg);

Instead of performing some of the conversions here and some of them as part of 
initialization, I think it'd be more obvious to compute the builtin's parameter 
type here (which is the type of the argument if it's not of array [or function] 
type, and the decayed type of the argument otherwise), and do the decay and 
lvalue-to-rvalue conversion as part of the parameter initialization below.

The current code arrangement (and especially this comment) leaves a reader 
thinking "but you *need* an lvalue-to-rvalue conversion if the argument is an 
lvalue".



Comment at: lib/Sema/SemaChecking.cpp:935
   return true;
+
 }

Did you mean to add this blank line?



Comment at: test/CodeGen/builtins.c:404-409
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: store i32* [[TMP]], i32** %d

This test is not robust against minor IR differences such as variable or basic 
block names changing (some of these change in a release build), and is testing 
things that are not related to this builtin (eg, that we produce an alloca for 
a function parameter and its relative order to an alloca for a local variable).

I would remove everything here other than the load and the store, and add an 
explicit check that we don't generate a launder call:

```
  // CHECK: [[TMP:%.*]] = load i32*,
  // CHECK-NOT: @llvm.launder
  // CHECK: store i32* [[TMP]],
```



Comment at: test/CodeGenCXX/builtin-launder.cpp:16
+extern "C" void test_builtin_launder_virtual_fn(TestVirtualFn *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca [[TYPE:%.*]], align 8

This is likewise likely to fail with a release build of clang.



Comment at: test/SemaCXX/builtins.cpp:120
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");

`` doesn't what?


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

https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-11-14 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

In https://reviews.llvm.org/D40218#1298943, @Romain-Geissler-1A wrote:

> Is there any news on this code review ? Is it ready to land ?


I think so, but there were some changes regarding incomplete types since 
Richard last looked at it.
I wanted him to sign off on the new behavior.




Comment at: lib/CodeGen/CGBuiltin.cpp:1037
+
+  // FIXME: We either have an incomplete class type, or we have a class 
template
+  // whose instantiation has not been forced. Example:

@rsmith I believe this changed since you approved the patch.

We talked about this offline, but could you give it a thumbs up?


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-11-14 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 174109.
EricWF added a comment.

Merge with upstream.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,72 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp, int ()[5]) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(Arr);
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -249,6 +249,24 @@
 return buf;
 }
 
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+  __builtin_launder(fn); // expected-error {{function pointer 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-11-14 Thread Romain Geissler via Phabricator via cfe-commits
Romain-Geissler-1A added a comment.

Hi,

Is there any news on this code review ? Is it ready to land ?

Cheers,
Romain


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-08-06 Thread Erich Keane via Phabricator via cfe-commits
erichkeane added a comment.

Bump!  I don't see anything here that seems questionable (and this has 
extensive testing), but I presume @rsmith should be the final one to approve.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-05-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 147639.
EricWF added a comment.

- Handle array types as requested.

- Attempt to handle incomplete class types. They are always considered in need 
of laundering. Including class templates who's instantiation hasn't been forced 
yet. @rsmith is this the correct thing to do?


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,72 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp, int ()[5]) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder(Arr);
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -249,6 +249,24 @@
 return buf;
 }
 
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-05-14 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added a comment.

Also we probably want to hold off on landing this until PR37458 is fixed, 
otherwise `std::launder` will start miscompiling code.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-05-14 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.

LGTM with a fix (and test) for pointer-to-array-of-dynamic-class-type handling.




Comment at: lib/CodeGen/CGBuiltin.cpp:936-938
+  const auto *Record = Ty->getAsCXXRecordDecl();
+  if (!Record || !Seen.insert(Record).second)
+return false;

I think you also need to recurse through array types (use 
`Ty->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()` or similar).


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-04-03 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

Ping.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-03-21 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 139363.
EricWF marked an inline comment as done.
EricWF added a comment.

- Launder types with subobjects of dynamic class type.
- Improve diagnostic selection using `llvm::Optional`.
- Add comment about LTO ABI concerns to test file.
- Merge with master.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,71 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo)  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,21 @@
 
 return buf;
 }
+
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-03-21 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked 2 inline comments as done.
EricWF added inline comments.



Comment at: test/CodeGenCXX/builtin-launder.cpp:93-96
+/// The test cases in this namespace technically need to be laundered according
+/// to the language in the standard (ie they have const or reference 
subobjects)
+/// but LLVM doesn't currently optimize on these cases -- so Clang emits
+/// __builtin_launder as a nop.

rsmith wrote:
> I would note that this means adding optimizations for those cases later is an 
> LTO ABI break. That's probably OK, but just something we're going to need to 
> remember.
I added your note almost verbatim to the test case.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-03-21 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF marked an inline comment as done.
EricWF added inline comments.



Comment at: lib/CodeGen/CGBuiltin.cpp:1947-1948
+const auto *Record = ArgTy->getAsCXXRecordDecl();
+if (CGM.getCodeGenOpts().StrictVTablePointers && Record &&
+Record->isDynamicClass())
+  Ptr = Builder.CreateInvariantGroupBarrier(Ptr);

rsmith wrote:
> I think you also need to catch class types that contain dynamic classes as 
> subobjects.
Only by-value subobjects, or also reference subobjects?


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-02-23 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/CodeGen/CGBuiltin.cpp:1947-1948
+const auto *Record = ArgTy->getAsCXXRecordDecl();
+if (CGM.getCodeGenOpts().StrictVTablePointers && Record &&
+Record->isDynamicClass())
+  Ptr = Builder.CreateInvariantGroupBarrier(Ptr);

I think you also need to catch class types that contain dynamic classes as 
subobjects.



Comment at: lib/Sema/SemaChecking.cpp:860
+
+  int DiagSelect = [&]() {
+if (!ArgTy->isPointerType())

Might be a bit clearer to use `llvm::Optional` as the type of this.



Comment at: test/CodeGenCXX/builtin-launder.cpp:93-96
+/// The test cases in this namespace technically need to be laundered according
+/// to the language in the standard (ie they have const or reference 
subobjects)
+/// but LLVM doesn't currently optimize on these cases -- so Clang emits
+/// __builtin_launder as a nop.

I would note that this means adding optimizations for those cases later is an 
LTO ABI break. That's probably OK, but just something we're going to need to 
remember.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-02-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 134986.
EricWF added a comment.

Ping.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,71 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo)  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,21 @@
 
 return buf;
 }
+
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+  __builtin_launder(fn); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+}
Index: 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 133290.
EricWF added a comment.

- Rebase off master.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,71 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo)  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,21 @@
 
 return buf;
 }
+
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+  __builtin_launder(fn); // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+}

[PATCH] D40218: [Clang] Add __builtin_launder

2018-02-07 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added a comment.

Ping.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2018-01-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 129742.
EricWF added a comment.

- Improve diagnostic handling.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,71 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp) {
+  __builtin_launder(vp);   // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(fnp);  // expected-error {{function pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(foo)  // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,21 @@
 
 return buf;
 }
+
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder' is not allowed}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp);  // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  __builtin_launder(cvp); // expected-error {{void pointer argument to '__builtin_launder' is not allowed}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+  __builtin_launder(fn); // expected-error {{function pointer argument to '__builtin_launder' is not 

[PATCH] D40218: [Clang] Add __builtin_launder

2018-01-12 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 129740.
EricWF marked an inline comment as done.
EricWF added a comment.

- Address inline comments about missing diagnostics for void pointers and 
function pointers.
- Address inline comments about only enabling when `-fstrict-vtable-pointers` 
is specified, and only on types with vtables.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/CodeGenCXX/builtin-launder.cpp
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,71 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+struct Dummy {};
+
+using FnType = int(char);
+using MemFnType = int (Dummy::*)(char);
+using ConstMemFnType = int (Dummy::*)() const;
+
+void foo() {}
+
+void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
+MemFnType mfp, ConstMemFnType cmfp) {
+  __builtin_launder(vp);   // expected-error {{argument to '__builtin_launder' cannot be a void pointer}}
+  __builtin_launder(cvp);  // expected-error {{argument to '__builtin_launder' cannot be a void pointer}}
+  __builtin_launder(fnp);  // expected-error {{argument to '__builtin_launder' cannot be a function pointer}}
+  __builtin_launder(mfp);  // expected-error {{non-pointer argument to '__builtin_launder'}}
+  __builtin_launder(cmfp); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  (void)__builtin_launder();
+  __builtin_launder(42);  // expected-error {{non-pointer argument to '__builtin_launder'}}
+  __builtin_launder(nullptr); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  __builtin_launder(foo) // expected-error {{non-pointer argument to '__builtin_launder'}}
+}
+
+void test_builtin_launder(char *p, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,21 @@
 
 return buf;
 }
+
+typedef void (fn_t)(int);
+
+void test_builtin_launder(char *p, void *vp, const void *cvp,
+  const volatile int *ip, float *restrict fp,
+  fn_t *fn) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  char *d = __builtin_launder(p);
+  __builtin_launder(vp); // expected-error {{argument to '__builtin_launder' cannot be a void pointer}}
+  __builtin_launder(cvp); // expected-error {{argument to '__builtin_launder' cannot be a void pointer}}
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+ 

[PATCH] D40218: [Clang] Add __builtin_launder

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



Comment at: lib/CodeGen/CGBuiltin.cpp:1674
+Value *Ptr = EmitScalarExpr(E->getArg(0));
+Ptr = Builder.CreateInvariantGroupBarrier(Ptr);
+return RValue::get(Ptr);

rsmith wrote:
> It would be nice to avoid this for types that contain no const subobjects / 
> reference subobjects / vptrs. I think we can also omit this entirely if 
> `-fstrict-vtable-ptrs` is disabled, since in that case we don't generate any 
> `invariant.group` metadata.
> 
> I'd be OK with the former being left to a future change, but the latter 
> should be part of this change so we don't generate unnecessarily-inefficient 
> code in the default mode for uses of `std::launder`.
I'll put it in this change set.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2017-12-07 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: lib/CodeGen/CGBuiltin.cpp:1674
+Value *Ptr = EmitScalarExpr(E->getArg(0));
+Ptr = Builder.CreateInvariantGroupBarrier(Ptr);
+return RValue::get(Ptr);

It would be nice to avoid this for types that contain no const subobjects / 
reference subobjects / vptrs. I think we can also omit this entirely if 
`-fstrict-vtable-ptrs` is disabled, since in that case we don't generate any 
`invariant.group` metadata.

I'd be OK with the former being left to a future change, but the latter should 
be part of this change so we don't generate unnecessarily-inefficient code in 
the default mode for uses of `std::launder`.



Comment at: lib/Sema/SemaChecking.cpp:860-864
+  if (!ArgTy->isPointerType()) {
+S.Diag(TheCall->getLocStart(), diag::err_builtin_launder_non_pointer_arg)
+<< TheCall->getSourceRange();
+return ExprError();
+  }

Please also check that the pointee type is an object type -- per 
[ptr.launder]p3, "the program is ill-formed if T is a function type or cv 
void", and we don't want our builtin to need to deal with such cases.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-20 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 123627.
EricWF added a comment.

- Improve quality of tests.
- Format code.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,52 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(vp, void*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,15 @@
 
 return buf;
 }
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, float *restrict fp) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+}
Index: test/Preprocessor/feature_tests.c
===
--- test/Preprocessor/feature_tests.c
+++ test/Preprocessor/feature_tests.c
@@ -14,6 +14,7 @@
  !__has_builtin(__builtin_convertvector) || \
  !__has_builtin(__builtin_trap) || \
  !__has_builtin(__c11_atomic_init) || \
+ !__has_builtin(__builtin_launder) || \
  !__has_feature(attribute_analyzer_noreturn) || \
  !__has_feature(attribute_overloadable)
 #error Clang should have these
Index: test/CodeGen/builtins.c
===
--- test/CodeGen/builtins.c
+++ test/CodeGen/builtins.c
@@ -132,6 +132,8 @@
   R(extract_return_addr, ());
   P(signbit, (1.0));
 
+  R(launder, ());
+
   return 0;
 }
 
@@ -396,6 +398,20 @@
   return __builtin_readcyclecounter();
 }
 
+// CHECK-LABEL: define void @test_builtin_launder
+void test_builtin_launder(int *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP]] to i8*
+  // CHECK-NEXT: [[TMP2:%.*]] = call i8* @llvm.invariant.group.barrier.p0i8(i8* [[TMP1]])
+  // CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
+  // CHECK-NEXT: store i32* [[TMP3]], i32** %d
+  int *d = __builtin_launder(p);
+}
+
 // Behavior of __builtin_os_log differs between platforms, so only test on X86
 #ifdef __x86_64__
 
Index: lib/Sema/SemaChecking.cpp

[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 123516.
EricWF added a comment.

- Fix argument initialization.
- Make constexpr.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 -fcxx-exceptions
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++14 -fcxx-exceptions
 // RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++1z -fcxx-exceptions
 typedef const struct __CFString * CFStringRef;
 #define CFSTR __builtin___CFStringMakeConstantString
@@ -53,3 +53,52 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+namespace test_launder {
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, const float *,
+  double *__restrict dp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+#define TEST_TYPE(Ptr, Type) \
+  static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+  TEST_TYPE(p, char*);
+  TEST_TYPE(vp, void*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  TEST_TYPE(dp, double *__restrict);
+#undef TEST_TYPE
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+template 
+constexpr Tp *test_constexpr_launder(Tp *tp) {
+  return __builtin_launder(tp);
+}
+constexpr int const_int = 42;
+constexpr int const_int2 = 101;
+constexpr const int *const_ptr = test_constexpr_launder(_int);
+static_assert(_int == const_ptr, "");
+static_assert(const_ptr != test_constexpr_launder(_int2), "");
+
+void test_non_constexpr() {
+  constexpr int i = 42;// expected-note {{declared here}}
+  constexpr const int *ip = __builtin_launder(); // expected-error {{constexpr variable 'ip' must be initialized by a constant expression}}
+  // expected-note@-1 {{pointer to 'i' is not a constant expression}}
+}
+
+constexpr bool test_in_constexpr(const int ) {
+  return (__builtin_launder() == );
+}
+static_assert(test_in_constexpr(const_int), "");
+void f() {
+  constexpr int i = 42;
+  // FIXME: Should this work? Since `` doesn't.
+  static_assert(test_in_constexpr(i), "");
+}
+
+} // end namespace test_launder
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,15 @@
 
 return buf;
 }
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, float *restrict fp) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+  float *fd = __builtin_launder(fp);
+}
Index: test/Preprocessor/feature_tests.c
===
--- test/Preprocessor/feature_tests.c
+++ test/Preprocessor/feature_tests.c
@@ -14,6 +14,7 @@
  !__has_builtin(__builtin_convertvector) || \
  !__has_builtin(__builtin_trap) || \
  !__has_builtin(__c11_atomic_init) || \
+ !__has_builtin(__builtin_launder) || \
  !__has_feature(attribute_analyzer_noreturn) || \
  !__has_feature(attribute_overloadable)
 #error Clang should have these
Index: test/CodeGen/builtins.c
===
--- test/CodeGen/builtins.c
+++ test/CodeGen/builtins.c
@@ -132,6 +132,8 @@
   R(extract_return_addr, ());
   P(signbit, (1.0));
 
+  R(launder, ());
+
   return 0;
 }
 
@@ -396,6 +398,20 @@
   return __builtin_readcyclecounter();
 }
 
+// CHECK-LABEL: define void @test_builtin_launder
+void test_builtin_launder(int *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP]] to i8*
+  // CHECK-NEXT: [[TMP2:%.*]] = call i8* 

[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-19 Thread Jonathan Roelofs via Phabricator via cfe-commits
jroelofs added inline comments.



Comment at: include/clang/Basic/Builtins.def:480
 BUILTIN(__builtin_thread_pointer, "v*", "nc")
+BUILTIN(__builtin_launder, "v*v*", "nt")
 

EricWF wrote:
> jroelofs wrote:
> > GCC's is type-generic:
> > 
> > ```
> > #include 
> > 
> > bool is_type_generic() {
> >   int v;
> >   return std::is_same >   decltype()>::value;
> > }
> > ```
> > 
> > However this `BUILTIN` line says that this one is not (yeah, I see it's 
> > being fixed up in Sema later in this patch). I think you need to use custom 
> > type checking here via `t`.
> The `t` is specified. It's in the third argument. 
ohhh. duh. sorry.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-19 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF added inline comments.



Comment at: include/clang/Basic/Builtins.def:480
 BUILTIN(__builtin_thread_pointer, "v*", "nc")
+BUILTIN(__builtin_launder, "v*v*", "nt")
 

jroelofs wrote:
> GCC's is type-generic:
> 
> ```
> #include 
> 
> bool is_type_generic() {
>   int v;
>   return std::is_same   decltype()>::value;
> }
> ```
> 
> However this `BUILTIN` line says that this one is not (yeah, I see it's being 
> fixed up in Sema later in this patch). I think you need to use custom type 
> checking here via `t`.
The `t` is specified. It's in the third argument. 


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-19 Thread Jonathan Roelofs via Phabricator via cfe-commits
jroelofs added inline comments.



Comment at: include/clang/Basic/Builtins.def:480
 BUILTIN(__builtin_thread_pointer, "v*", "nc")
+BUILTIN(__builtin_launder, "v*v*", "nt")
 

GCC's is type-generic:

```
#include 

bool is_type_generic() {
  int v;
  return std::is_same::value;
}
```

However this `BUILTIN` line says that this one is not (yeah, I see it's being 
fixed up in Sema later in this patch). I think you need to use custom type 
checking here via `t`.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-19 Thread David Majnemer via Phabricator via cfe-commits
majnemer added a comment.

A test with restrict and __restrict might be interesting.


https://reviews.llvm.org/D40218



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


[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF updated this revision to Diff 123484.
EricWF added a comment.

- Remove incorrect FIXME comment.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,22 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+#define TEST_TYPE(Ptr, Type) \
+static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, const float*& fp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  TEST_TYPE(p, char*);
+  TEST_TYPE(vp, void*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+#undef TEST_TYPE
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,14 @@
 
 return buf;
 }
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+}
Index: test/Preprocessor/feature_tests.c
===
--- test/Preprocessor/feature_tests.c
+++ test/Preprocessor/feature_tests.c
@@ -14,6 +14,7 @@
  !__has_builtin(__builtin_convertvector) || \
  !__has_builtin(__builtin_trap) || \
  !__has_builtin(__c11_atomic_init) || \
+ !__has_builtin(__builtin_launder) || \
  !__has_feature(attribute_analyzer_noreturn) || \
  !__has_feature(attribute_overloadable)
 #error Clang should have these
Index: test/CodeGen/builtins.c
===
--- test/CodeGen/builtins.c
+++ test/CodeGen/builtins.c
@@ -132,6 +132,8 @@
   R(extract_return_addr, ());
   P(signbit, (1.0));
 
+  R(launder, ());
+
   return 0;
 }
 
@@ -396,6 +398,20 @@
   return __builtin_readcyclecounter();
 }
 
+// CHECK-LABEL: define void @test_builtin_launder
+void test_builtin_launder(int *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP]] to i8*
+  // CHECK-NEXT: [[TMP2:%.*]] = call i8* @llvm.invariant.group.barrier.p0i8(i8* [[TMP1]])
+  // CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
+  // CHECK-NEXT: store i32* [[TMP3]], i32** %d
+  int *d = __builtin_launder(p);
+}
+
 // Behavior of __builtin_os_log differs between platforms, so only test on X86
 #ifdef __x86_64__
 
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -850,6 +850,19 @@
   return false;
 }
 
+static bool SemaBuiltinLaunder(Sema& S, CallExpr *TheCall) {
+  if (checkArgCount(S, TheCall, 1)) return true;
+  Expr *Arg = TheCall->getArg(0);
+  QualType ArgT = Arg->getType();
+  if (!ArgT->isPointerType()) {
+S.Diag(TheCall->getLocStart(), diag::err_builtin_launder_non_pointer_arg)
+<< TheCall->getSourceRange();
+return true;
+  }
+  TheCall->setType(Arg->getType());
+  return false; // OK
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
@@ -967,6 +980,10 @@
 if (checkArgCount(*this, TheCall, 1)) return true;
 TheCall->setType(Context.IntTy);
 break;
+  case Builtin::BI__builtin_launder:
+if (SemaBuiltinLaunder(*this, TheCall))
+  return ExprError();
+break;
   case Builtin::BI__sync_fetch_and_add:
   case Builtin::BI__sync_fetch_and_add_1:
   case Builtin::BI__sync_fetch_and_add_2:
Index: lib/CodeGen/CGBuiltin.cpp

[PATCH] D40218: [Clang] Add __builtin_launder

2017-11-18 Thread Eric Fiselier via Phabricator via cfe-commits
EricWF created this revision.
Herald added a subscriber: Prazek.

This patch adds `__builtin_launder`, which is required to implement 
`std::launder`. Additionally GCC provides `__builtin_launder`, so thing brings 
Clang in-line with GCC.

I'm not exactly sure what magic `__builtin_launder` requires, but  based on 
previous discussions this patch applies a `@llvm.invariant.group.barrier`. As 
noted in previous discussions, this may not be enough to correctly handle 
vtables.


https://reviews.llvm.org/D40218

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  test/CodeGen/builtins.c
  test/Preprocessor/feature_tests.c
  test/Sema/builtins.c
  test/SemaCXX/builtins.cpp

Index: test/SemaCXX/builtins.cpp
===
--- test/SemaCXX/builtins.cpp
+++ test/SemaCXX/builtins.cpp
@@ -53,3 +53,22 @@
 void synchronize_args() {
   __sync_synchronize(0); // expected-error {{too many arguments}}
 }
+
+#define TEST_TYPE(Ptr, Type) \
+static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip, const float*& fp) {
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  TEST_TYPE(p, char*);
+  TEST_TYPE(vp, void*);
+  TEST_TYPE(ip, const volatile int*);
+  TEST_TYPE(fp, const float*);
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
+  const float* fd = __builtin_launder(fp);
+}
+
+#undef TEST_TYPE
Index: test/Sema/builtins.c
===
--- test/Sema/builtins.c
+++ test/Sema/builtins.c
@@ -248,3 +248,14 @@
 
 return buf;
 }
+
+void test_builtin_launder(char *p, void *vp, const volatile int *ip) {
+  __builtin_launder(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_launder(p, p); // expected-error {{too many arguments to function call, expected 1, have 2}}
+  int x;
+  __builtin_launder(x); // expected-error {{non-pointer argument to '__builtin_launder'}}
+  char *d = __builtin_launder(p);
+  void *vd = __builtin_launder(vp);
+  const volatile int *id = __builtin_launder(ip);
+  int *id2 = __builtin_launder(ip); // expected-warning {{discards qualifiers}}
+}
Index: test/Preprocessor/feature_tests.c
===
--- test/Preprocessor/feature_tests.c
+++ test/Preprocessor/feature_tests.c
@@ -14,6 +14,7 @@
  !__has_builtin(__builtin_convertvector) || \
  !__has_builtin(__builtin_trap) || \
  !__has_builtin(__c11_atomic_init) || \
+ !__has_builtin(__builtin_launder) || \
  !__has_feature(attribute_analyzer_noreturn) || \
  !__has_feature(attribute_overloadable)
 #error Clang should have these
Index: test/CodeGen/builtins.c
===
--- test/CodeGen/builtins.c
+++ test/CodeGen/builtins.c
@@ -132,6 +132,8 @@
   R(extract_return_addr, ());
   P(signbit, (1.0));
 
+  R(launder, ());
+
   return 0;
 }
 
@@ -396,6 +398,20 @@
   return __builtin_readcyclecounter();
 }
 
+// CHECK-LABEL: define void @test_builtin_launder
+void test_builtin_launder(int *p) {
+  // CHECK: entry
+  // CHECK-NEXT: %p.addr = alloca i32*
+  // CHECK-NEXT: %d = alloca i32*
+  // CHECK-NEXT: store i32* %p, i32** %p.addr, align 8
+  // CHECK-NEXT: [[TMP:%.*]] = load i32*, i32** %p.addr
+  // CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP]] to i8*
+  // CHECK-NEXT: [[TMP2:%.*]] = call i8* @llvm.invariant.group.barrier.p0i8(i8* [[TMP1]])
+  // CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
+  // CHECK-NEXT: store i32* [[TMP3]], i32** %d
+  int *d = __builtin_launder(p);
+}
+
 // Behavior of __builtin_os_log differs between platforms, so only test on X86
 #ifdef __x86_64__
 
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -850,6 +850,20 @@
   return false;
 }
 
+static bool SemaBuiltinLaunder(Sema& S, CallExpr *TheCall) {
+  if (checkArgCount(S, TheCall, 1)) return true;
+  Expr *Arg = TheCall->getArg(0);
+  QualType ArgT = Arg->getType();
+  if (!ArgT->isPointerType()) {
+S.Diag(TheCall->getLocStart(), diag::err_builtin_launder_non_pointer_arg)
+<< TheCall->getSourceRange();
+return true;
+  }
+  TheCall->setType(Arg->getType());
+  // FIXME: Add attributes to argument
+  return false; // OK
+}
+
 ExprResult
 Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
@@ -967,6 +981,10 @@
 if