[clang] [clang][Interp] Implement __builtin_addressof (PR #77303)
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)
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)
@@ -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)
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)
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)
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)
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