aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimm Baeder <tbaeder@redhat.com>2025-04-29 10:57:30 +0200
committerGitHub <noreply@github.com>2025-04-29 10:57:30 +0200
commit4bf356bbd25ef5950de92b9e66cc8a2d3af583d9 (patch)
tree229e492b64d5bdfadb833164f4a62b5c41c10a32
parent13b443f2efcfe57768a1077c63bb675eb6380e35 (diff)
downloadllvm-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.cpp49
-rw-r--r--clang/test/AST/ByteCode/builtin-functions.cpp33
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