Skip to content

[clang][Interp] Implement __builtin_addressof #77303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
if (CurFunc->isUnevaluatedBuiltin())
return;

// Some builtin functions require us to only look at the call site, since
// the classified parameter types do not match.
if (CurFunc->isBuiltin()) {
const auto *CE =
cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
const Expr *A = CE->getArg(I);
popArg(S, A);
}
return;
}

if (S.Current->Caller && CurFunc->isVariadic()) {
// CallExpr we're look for is at the return PC of the current function, i.e.
// in the caller.
Expand Down
33 changes: 30 additions & 3 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
case X: \
return Ret<X>(S, OpPC, Result);
switch (*T) {
RET_CASE(PT_Ptr);
RET_CASE(PT_FnPtr);
RET_CASE(PT_Float);
RET_CASE(PT_Bool);
RET_CASE(PT_Sint8);
Expand Down Expand Up @@ -613,15 +615,34 @@ static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
PrimType PtrT =
S.getContext().classify(Call->getArg(0)->getType()).value_or(PT_Ptr);

if (PtrT == PT_FnPtr) {
const FunctionPointer &Arg = S.Stk.peek<FunctionPointer>();
S.Stk.push<FunctionPointer>(Arg);
} else if (PtrT == PT_Ptr) {
const Pointer &Arg = S.Stk.peek<Pointer>();
S.Stk.push<Pointer>(Arg);
} else {
assert(false && "Unsupported pointer type passed to __builtin_addressof()");
}
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
InterpFrame *Frame = S.Current;
APValue Dummy;

QualType ReturnType = Call->getCallReturnType(S.getCtx());
std::optional<PrimType> ReturnT = S.getContext().classify(ReturnType);
std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType());

// If classify failed, we assume void.
assert(ReturnT || ReturnType->isVoidType());
assert(ReturnT || Call->getType()->isVoidType());

switch (F->getBuiltinID()) {
case Builtin::BI__builtin_is_constant_evaluated:
Expand Down Expand Up @@ -820,6 +841,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
if (!interp__builtin_ffs(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BIaddressof:
case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
if (!interp__builtin_addressof(S, OpPC, Frame, F, Call))
return false;
break;

default:
return false;
Expand Down
24 changes: 24 additions & 0 deletions clang/test/AST/Interp/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,3 +389,27 @@ namespace Packs {
static_assert(foo<int, char>() == 2, "");
static_assert(foo<>() == 0, "");
}

namespace AddressOf {
struct S {} s;
static_assert(__builtin_addressof(s) == &s, "");

struct T { constexpr T *operator&() const { return nullptr; } int n; } t;
constexpr T *pt = __builtin_addressof(t);
static_assert(&pt->n == &t.n, "");

struct U { int n : 5; } u;
int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}} \
// ref-error {{address of bit-field requested}}

S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}} \
// expected-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}} \
// ref-error {{taking the address of a temporary}} \
// ref-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}}

constexpr int foo() {return 1;}
static_assert(__builtin_addressof(foo) == foo, "");

constexpr _Complex float F = {3, 4};
static_assert(__builtin_addressof(F) == &F, "");
}