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

Conversation

tbaederr
Copy link
Contributor

@tbaederr tbaederr commented Jan 8, 2024

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.

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.
@tbaederr tbaederr added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2024

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/77303.diff

3 Files Affected:

  • (modified) clang/lib/AST/Interp/Interp.cpp (+12)
  • (modified) clang/lib/AST/Interp/InterpBuiltin.cpp (+30-3)
  • (modified) clang/test/AST/Interp/functions.cpp (+24)
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 21ea2503b94bff..9de0926b9dba9c 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -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.
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index b55b1569a25983..d8df81961cc813 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -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);
@@ -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);
+  }
+  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:
@@ -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;
diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp
index 179a195098b132..75f3c5d192b2cf 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -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, "");
+}

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo comment

@tbaederr tbaederr merged commit e3993e0 into llvm:main Jan 11, 2024
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants