Skip to content

Commit 6728207

Browse files
committed
[clang][Interp] Implement __builtin_launder
Just forward the pointer. Copy tests from SemaCXX
1 parent 266bbc2 commit 6728207

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,15 @@ static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC,
658658
return true;
659659
}
660660

661+
static bool interp__builtin_launder(InterpState &S, CodePtr OpPC,
662+
const InterpFrame *Frame,
663+
const Function *Func,
664+
const CallExpr *Call) {
665+
const Pointer &Arg = S.Stk.peek<Pointer>();
666+
S.Stk.push<Pointer>(Arg);
667+
return true;
668+
}
669+
661670
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
662671
const CallExpr *Call) {
663672
InterpFrame *Frame = S.Current;
@@ -887,6 +896,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
887896
return false;
888897
break;
889898

899+
case Builtin::BI__builtin_launder:
900+
if (!interp__builtin_launder(S, OpPC, Frame, F, Call))
901+
return false;
902+
break;
903+
890904
default:
891905
return false;
892906
}

clang/test/AST/Interp/builtin-functions.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,96 @@ namespace EhReturnDataRegno {
351351
__builtin_eh_return_data_regno(X); // both-error {{argument to '__builtin_eh_return_data_regno' must be a constant integer}}
352352
}
353353
}
354+
355+
/// From test/SemaCXX/builtins.cpp
356+
namespace test_launder {
357+
#define TEST_TYPE(Ptr, Type) \
358+
static_assert(__is_same(decltype(__builtin_launder(Ptr)), Type), "expected same type")
359+
360+
struct Dummy {};
361+
362+
using FnType = int(char);
363+
using MemFnType = int (Dummy::*)(char);
364+
using ConstMemFnType = int (Dummy::*)() const;
365+
366+
void foo() {}
367+
368+
void test_builtin_launder_diags(void *vp, const void *cvp, FnType *fnp,
369+
MemFnType mfp, ConstMemFnType cmfp, int (&Arr)[5]) {
370+
__builtin_launder(vp); // both-error {{void pointer argument to '__builtin_launder' is not allowed}}
371+
__builtin_launder(cvp); // both-error {{void pointer argument to '__builtin_launder' is not allowed}}
372+
__builtin_launder(fnp); // both-error {{function pointer argument to '__builtin_launder' is not allowed}}
373+
__builtin_launder(mfp); // both-error {{non-pointer argument to '__builtin_launder' is not allowed}}
374+
__builtin_launder(cmfp); // both-error {{non-pointer argument to '__builtin_launder' is not allowed}}
375+
(void)__builtin_launder(&fnp);
376+
__builtin_launder(42); // both-error {{non-pointer argument to '__builtin_launder' is not allowed}}
377+
__builtin_launder(nullptr); // both-error {{non-pointer argument to '__builtin_launder' is not allowed}}
378+
__builtin_launder(foo); // both-error {{function pointer argument to '__builtin_launder' is not allowed}}
379+
(void)__builtin_launder(Arr);
380+
}
381+
382+
void test_builtin_launder(char *p, const volatile int *ip, const float *&fp,
383+
double *__restrict dp) {
384+
int x;
385+
__builtin_launder(x); // both-error {{non-pointer argument to '__builtin_launder' is not allowed}}
386+
387+
TEST_TYPE(p, char*);
388+
TEST_TYPE(ip, const volatile int*);
389+
TEST_TYPE(fp, const float*);
390+
TEST_TYPE(dp, double *__restrict);
391+
392+
char *d = __builtin_launder(p);
393+
const volatile int *id = __builtin_launder(ip);
394+
int *id2 = __builtin_launder(ip); // both-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const volatile int *'}}
395+
const float* fd = __builtin_launder(fp);
396+
}
397+
398+
void test_launder_return_type(const int (&ArrayRef)[101], int (&MArrRef)[42][13],
399+
void (**&FuncPtrRef)()) {
400+
TEST_TYPE(ArrayRef, const int *);
401+
TEST_TYPE(MArrRef, int(*)[13]);
402+
TEST_TYPE(FuncPtrRef, void (**)());
403+
}
404+
405+
template <class Tp>
406+
constexpr Tp *test_constexpr_launder(Tp *tp) {
407+
return __builtin_launder(tp);
408+
}
409+
constexpr int const_int = 42;
410+
constexpr int const_int2 = 101;
411+
constexpr const int *const_ptr = test_constexpr_launder(&const_int);
412+
static_assert(&const_int == const_ptr, "");
413+
static_assert(const_ptr != test_constexpr_launder(&const_int2), "");
414+
415+
void test_non_constexpr() {
416+
constexpr int i = 42; // both-note {{address of non-static constexpr variable 'i' may differ on each invocation}}
417+
constexpr const int *ip = __builtin_launder(&i); // both-error {{constexpr variable 'ip' must be initialized by a constant expression}}
418+
// both-note@-1 {{pointer to 'i' is not a constant expression}}
419+
}
420+
421+
constexpr bool test_in_constexpr(const int &i) {
422+
return (__builtin_launder(&i) == &i);
423+
}
424+
425+
static_assert(test_in_constexpr(const_int), "");
426+
void f() {
427+
constexpr int i = 42;
428+
static_assert(test_in_constexpr(i), "");
429+
}
430+
431+
struct Incomplete; // both-note {{forward declaration}}
432+
struct IncompleteMember {
433+
Incomplete &i;
434+
};
435+
void test_incomplete(Incomplete *i, IncompleteMember *im) {
436+
// both-error@+1 {{incomplete type 'Incomplete' where a complete type is required}}
437+
__builtin_launder(i);
438+
__builtin_launder(&i); // OK
439+
__builtin_launder(im); // OK
440+
}
441+
442+
void test_noexcept(int *i) {
443+
static_assert(noexcept(__builtin_launder(i)), "");
444+
}
445+
#undef TEST_TYPE
446+
} // end namespace test_launder

0 commit comments

Comments
 (0)