[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-11 Thread Timm Baeder via cfe-commits
Timm =?utf-8?q?Bäder?= 
Message-ID:
In-Reply-To: 


https://github.com/tbaederr closed 
https://github.com/llvm/llvm-project/pull/77303
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-10 Thread Timm Baeder via cfe-commits
Timm =?utf-8?q?Bäder?= 
Message-ID:
In-Reply-To: 


https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/77303

>From aa7ebd9f13d8b7a58f87dc8b00b99acca7f69196 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= 
Date: Mon, 11 Dec 2023 15:12:37 +0100
Subject: [PATCH 1/2] [clang][Interp] Implement __builtin_addressof

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.
---
 clang/lib/AST/Interp/Interp.cpp| 12 ++
 clang/lib/AST/Interp/InterpBuiltin.cpp | 33 +++---
 clang/test/AST/Interp/functions.cpp| 24 +++
 3 files changed, 66 insertions(+), 3 deletions(-)

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(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(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();
+S.Stk.push(Arg);
+  } else if (PtrT == PT_Ptr) {
+const Pointer &Arg = S.Stk.peek();
+S.Stk.push(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 ReturnT = S.getContext().classify(ReturnType);
+  std::optional 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() == 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 us

[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-09 Thread via cfe-commits


@@ -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();
+S.Stk.push(Arg);
+  } else if (PtrT == PT_Ptr) {
+const Pointer &Arg = S.Stk.peek();
+S.Stk.push(Arg);
+  } else {
+assert(false);

cor3ntin wrote:

can you add a string in there ?

https://github.com/llvm/llvm-project/pull/77303
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-09 Thread via cfe-commits

https://github.com/cor3ntin edited 
https://github.com/llvm/llvm-project/pull/77303
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-09 Thread via cfe-commits

https://github.com/cor3ntin approved this pull request.

LGTM modulo comment

https://github.com/llvm/llvm-project/pull/77303
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-08 Thread via cfe-commits

llvmbot wrote:




@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
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(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(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();
+S.Stk.push(Arg);
+  } else if (PtrT == PT_Ptr) {
+const Pointer &Arg = S.Stk.peek();
+S.Stk.push(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 ReturnT = S.getContext().classify(ReturnType);
+  std::optional 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() == 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-w

[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)

2024-01-08 Thread Timm Baeder via cfe-commits

https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/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.

>From aa7ebd9f13d8b7a58f87dc8b00b99acca7f69196 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= 
Date: Mon, 11 Dec 2023 15:12:37 +0100
Subject: [PATCH] [clang][Interp] Implement __builtin_addressof

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.
---
 clang/lib/AST/Interp/Interp.cpp| 12 ++
 clang/lib/AST/Interp/InterpBuiltin.cpp | 33 +++---
 clang/test/AST/Interp/functions.cpp| 24 +++
 3 files changed, 66 insertions(+), 3 deletions(-)

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(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(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();
+S.Stk.push(Arg);
+  } else if (PtrT == PT_Ptr) {
+const Pointer &Arg = S.Stk.peek();
+S.Stk.push(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 ReturnT = S.getContext().classify(ReturnType);
+  std::optional 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() == 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_add