[clang][bytecode] Start implementing builtin_is_within_lifetime (#137765)

This commit is contained in:
Timm Baeder
2025-04-29 10:57:30 +02:00
committed by GitHub
parent 13b443f2ef
commit 4bf356bbd2
2 changed files with 82 additions and 0 deletions

View File

@@ -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)

View File

@@ -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