Skip to content

Commit e3993e0

Browse files
authored
[clang][Interp] Implement __builtin_addressof (#77303)
We don't need to do anything here, since the input is already a Pointer. The only complexity is that we pre-classify the parameters as PT_Ptr, but they might end up being of a different pointer type, e.g. PT_FnPtr.
1 parent 3643d11 commit e3993e0

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

clang/lib/AST/Interp/Interp.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
134134
if (CurFunc->isUnevaluatedBuiltin())
135135
return;
136136

137+
// Some builtin functions require us to only look at the call site, since
138+
// the classified parameter types do not match.
139+
if (CurFunc->isBuiltin()) {
140+
const auto *CE =
141+
cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
142+
for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
143+
const Expr *A = CE->getArg(I);
144+
popArg(S, A);
145+
}
146+
return;
147+
}
148+
137149
if (S.Current->Caller && CurFunc->isVariadic()) {
138150
// CallExpr we're look for is at the return PC of the current function, i.e.
139151
// in the caller.

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
164164
case X: \
165165
return Ret<X>(S, OpPC, Result);
166166
switch (*T) {
167+
RET_CASE(PT_Ptr);
168+
RET_CASE(PT_FnPtr);
167169
RET_CASE(PT_Float);
168170
RET_CASE(PT_Bool);
169171
RET_CASE(PT_Sint8);
@@ -613,15 +615,34 @@ static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC,
613615
return true;
614616
}
615617

618+
static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC,
619+
const InterpFrame *Frame,
620+
const Function *Func,
621+
const CallExpr *Call) {
622+
PrimType PtrT =
623+
S.getContext().classify(Call->getArg(0)->getType()).value_or(PT_Ptr);
624+
625+
if (PtrT == PT_FnPtr) {
626+
const FunctionPointer &Arg = S.Stk.peek<FunctionPointer>();
627+
S.Stk.push<FunctionPointer>(Arg);
628+
} else if (PtrT == PT_Ptr) {
629+
const Pointer &Arg = S.Stk.peek<Pointer>();
630+
S.Stk.push<Pointer>(Arg);
631+
} else {
632+
assert(false && "Unsupported pointer type passed to __builtin_addressof()");
633+
}
634+
return true;
635+
}
636+
616637
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
617638
const CallExpr *Call) {
618639
InterpFrame *Frame = S.Current;
619640
APValue Dummy;
620641

621-
QualType ReturnType = Call->getCallReturnType(S.getCtx());
622-
std::optional<PrimType> ReturnT = S.getContext().classify(ReturnType);
642+
std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType());
643+
623644
// If classify failed, we assume void.
624-
assert(ReturnT || ReturnType->isVoidType());
645+
assert(ReturnT || Call->getType()->isVoidType());
625646

626647
switch (F->getBuiltinID()) {
627648
case Builtin::BI__builtin_is_constant_evaluated:
@@ -820,6 +841,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
820841
if (!interp__builtin_ffs(S, OpPC, Frame, F, Call))
821842
return false;
822843
break;
844+
case Builtin::BIaddressof:
845+
case Builtin::BI__addressof:
846+
case Builtin::BI__builtin_addressof:
847+
if (!interp__builtin_addressof(S, OpPC, Frame, F, Call))
848+
return false;
849+
break;
823850

824851
default:
825852
return false;

clang/test/AST/Interp/functions.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,3 +389,27 @@ namespace Packs {
389389
static_assert(foo<int, char>() == 2, "");
390390
static_assert(foo<>() == 0, "");
391391
}
392+
393+
namespace AddressOf {
394+
struct S {} s;
395+
static_assert(__builtin_addressof(s) == &s, "");
396+
397+
struct T { constexpr T *operator&() const { return nullptr; } int n; } t;
398+
constexpr T *pt = __builtin_addressof(t);
399+
static_assert(&pt->n == &t.n, "");
400+
401+
struct U { int n : 5; } u;
402+
int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}} \
403+
// ref-error {{address of bit-field requested}}
404+
405+
S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}} \
406+
// expected-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}} \
407+
// ref-error {{taking the address of a temporary}} \
408+
// ref-warning {{temporary whose address is used as value of local variable 'ptmp' will be destroyed at the end of the full-expression}}
409+
410+
constexpr int foo() {return 1;}
411+
static_assert(__builtin_addressof(foo) == foo, "");
412+
413+
constexpr _Complex float F = {3, 4};
414+
static_assert(__builtin_addressof(F) == &F, "");
415+
}

0 commit comments

Comments
 (0)