diff options
author | Timm Baeder <tbaeder@redhat.com> | 2025-04-29 10:57:30 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-29 10:57:30 +0200 |
commit | 4bf356bbd25ef5950de92b9e66cc8a2d3af583d9 (patch) | |
tree | 229e492b64d5bdfadb833164f4a62b5c41c10a32 | |
parent | 13b443f2efcfe57768a1077c63bb675eb6380e35 (diff) | |
download | llvm-4bf356bbd25ef5950de92b9e66cc8a2d3af583d9.zip llvm-4bf356bbd25ef5950de92b9e66cc8a2d3af583d9.tar.gz llvm-4bf356bbd25ef5950de92b9e66cc8a2d3af583d9.tar.bz2 |
[clang][bytecode] Start implementing builtin_is_within_lifetime (#137765)
-rw-r--r-- | clang/lib/AST/ByteCode/InterpBuiltin.cpp | 49 | ||||
-rw-r--r-- | clang/test/AST/ByteCode/builtin-functions.cpp | 33 |
2 files changed, 82 insertions, 0 deletions
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index b6e5b5f..8edc624 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2198,6 +2198,50 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC, + const CallExpr *Call) { + + if (!S.inConstantContext()) + return false; + + const Pointer &Ptr = S.Stk.peek<Pointer>(); + + auto Error = [&](int Diag) { + bool CalledFromStd = false; + const auto *Callee = S.Current->getCallee(); + if (Callee && Callee->isInStdNamespace()) { + const IdentifierInfo *Identifier = Callee->getIdentifier(); + CalledFromStd = Identifier && Identifier->isStr("is_within_lifetime"); + } + S.CCEDiag(CalledFromStd + ? S.Current->Caller->getSource(S.Current->getRetPC()) + : S.Current->getSource(OpPC), + diag::err_invalid_is_within_lifetime) + << (CalledFromStd ? "std::is_within_lifetime" + : "__builtin_is_within_lifetime") + << Diag; + return false; + }; + + if (Ptr.isZero()) + return Error(0); + if (Ptr.isOnePastEnd()) + return Error(1); + + bool Result = true; + if (!Ptr.isActive()) { + Result = false; + } else { + if (!CheckLive(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckMutable(S, OpPC, Ptr)) + return false; + } + + pushInteger(S, Result, Call->getType()); + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID) { if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID)) @@ -2707,6 +2751,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return false; break; + case Builtin::BI__builtin_is_within_lifetime: + if (!interp__builtin_is_within_lifetime(S, OpPC, Call)) + return false; + break; + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp index 46f9e48..21dca15 100644 --- a/clang/test/AST/ByteCode/builtin-functions.cpp +++ b/clang/test/AST/ByteCode/builtin-functions.cpp @@ -1709,3 +1709,36 @@ namespace Invalid { static_assert(test() == 0); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } + +#if __cplusplus >= 202002L +namespace WithinLifetime { + constexpr int a = 10; + static_assert(__builtin_is_within_lifetime(&a)); + + consteval int IsActive(bool ReadB) { + union { + int a, b; + } A; + A.a = 10; + if (ReadB) + return __builtin_is_within_lifetime(&A.b); + return __builtin_is_within_lifetime(&A.a); + } + static_assert(IsActive(false)); + static_assert(!IsActive(true)); + + static_assert(__builtin_is_within_lifetime((void*)nullptr)); // both-error {{not an integral constant expression}} \ + // both-note {{'__builtin_is_within_lifetime' cannot be called with a null pointer}} + + constexpr int i = 2; + constexpr int arr[2]{}; + void f() { + __builtin_is_within_lifetime(&i + 1); // both-error {{call to consteval function '__builtin_is_within_lifetime' is not a constant expression}} \ + // both-note {{'__builtin_is_within_lifetime' cannot be called with a one-past-the-end pointer}} \ + // both-warning {{expression result unused}} + __builtin_is_within_lifetime(arr + 2); // both-error {{call to consteval function '__builtin_is_within_lifetime' is not a constant expression}} \ + // both-note {{'__builtin_is_within_lifetime' cannot be called with a one-past-the-end pointer}} \ + // both-warning {{expression result unused}} + } +} +#endif |