[PATCH] D40218: [Clang] Add __builtin_launder
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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_samedecltype()>::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
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
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
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
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