682 lines · cpp
1//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Context.h"10#include "Boolean.h"11#include "ByteCodeEmitter.h"12#include "Compiler.h"13#include "EvalEmitter.h"14#include "Integral.h"15#include "InterpFrame.h"16#include "InterpHelpers.h"17#include "InterpStack.h"18#include "Pointer.h"19#include "PrimType.h"20#include "Program.h"21#include "clang/AST/ASTLambda.h"22#include "clang/AST/Expr.h"23#include "clang/Basic/TargetInfo.h"24 25using namespace clang;26using namespace clang::interp;27 28Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {29 this->ShortWidth = Ctx.getTargetInfo().getShortWidth();30 this->IntWidth = Ctx.getTargetInfo().getIntWidth();31 this->LongWidth = Ctx.getTargetInfo().getLongWidth();32 this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();33 assert(Ctx.getTargetInfo().getCharWidth() == 8 &&34 "We're assuming 8 bit chars");35}36 37Context::~Context() {}38 39bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {40 assert(Stk.empty());41 42 // Get a function handle.43 const Function *Func = getOrCreateFunction(FD);44 if (!Func)45 return false;46 47 // Compile the function.48 Compiler<ByteCodeEmitter>(*this, *P).compileFunc(49 FD, const_cast<Function *>(Func));50 51 if (!Func->isValid())52 return false;53 54 ++EvalID;55 // And run it.56 return Run(Parent, Func);57}58 59void Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,60 const FunctionDecl *FD) {61 assert(Stk.empty());62 ++EvalID;63 size_t StackSizeBefore = Stk.size();64 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);65 66 if (!C.interpretCall(FD, E)) {67 C.cleanup();68 Stk.clearTo(StackSizeBefore);69 }70}71 72bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {73 ++EvalID;74 bool Recursing = !Stk.empty();75 size_t StackSizeBefore = Stk.size();76 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);77 78 auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());79 80 if (Res.isInvalid()) {81 C.cleanup();82 Stk.clearTo(StackSizeBefore);83 return false;84 }85 86 if (!Recursing) {87 // We *can* actually get here with a non-empty stack, since88 // things like InterpState::noteSideEffect() exist.89 C.cleanup();90#ifndef NDEBUG91 // Make sure we don't rely on some value being still alive in92 // InterpStack memory.93 Stk.clearTo(StackSizeBefore);94#endif95 }96 97 Result = Res.stealAPValue();98 99 return true;100}101 102bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,103 ConstantExprKind Kind) {104 ++EvalID;105 bool Recursing = !Stk.empty();106 size_t StackSizeBefore = Stk.size();107 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);108 109 auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,110 /*DestroyToplevelScope=*/true);111 if (Res.isInvalid()) {112 C.cleanup();113 Stk.clearTo(StackSizeBefore);114 return false;115 }116 117 if (!Recursing) {118 assert(Stk.empty());119 C.cleanup();120#ifndef NDEBUG121 // Make sure we don't rely on some value being still alive in122 // InterpStack memory.123 Stk.clearTo(StackSizeBefore);124#endif125 }126 127 Result = Res.stealAPValue();128 return true;129}130 131bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,132 const Expr *Init, APValue &Result) {133 ++EvalID;134 bool Recursing = !Stk.empty();135 size_t StackSizeBefore = Stk.size();136 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);137 138 bool CheckGlobalInitialized =139 shouldBeGloballyIndexed(VD) &&140 (VD->getType()->isRecordType() || VD->getType()->isArrayType());141 auto Res = C.interpretDecl(VD, Init, CheckGlobalInitialized);142 if (Res.isInvalid()) {143 C.cleanup();144 Stk.clearTo(StackSizeBefore);145 146 return false;147 }148 149 if (!Recursing) {150 assert(Stk.empty());151 C.cleanup();152#ifndef NDEBUG153 // Make sure we don't rely on some value being still alive in154 // InterpStack memory.155 Stk.clearTo(StackSizeBefore);156#endif157 }158 159 Result = Res.stealAPValue();160 return true;161}162 163template <typename ResultT>164bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,165 const Expr *PtrExpr, ResultT &Result) {166 assert(Stk.empty());167 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);168 169 // Evaluate size value.170 APValue SizeValue;171 if (!evaluateAsRValue(Parent, SizeExpr, SizeValue))172 return false;173 174 if (!SizeValue.isInt())175 return false;176 uint64_t Size = SizeValue.getInt().getZExtValue();177 178 auto PtrRes = C.interpretAsPointer(PtrExpr, [&](const Pointer &Ptr) {179 if (Size == 0) {180 if constexpr (std::is_same_v<ResultT, APValue>)181 Result = APValue(APValue::UninitArray{}, 0, 0);182 return true;183 }184 185 if (!Ptr.isLive() || !Ptr.getFieldDesc()->isPrimitiveArray())186 return false;187 188 // Must be char.189 if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/)190 return false;191 192 if (Size > Ptr.getNumElems()) {193 Parent.FFDiag(SizeExpr, diag::note_constexpr_access_past_end) << AK_Read;194 Size = Ptr.getNumElems();195 }196 197 if constexpr (std::is_same_v<ResultT, APValue>) {198 QualType CharTy = PtrExpr->getType()->getPointeeType();199 Result = APValue(APValue::UninitArray{}, Size, Size);200 for (uint64_t I = 0; I != Size; ++I) {201 if (std::optional<APValue> ElemVal =202 Ptr.atIndex(I).toRValue(*this, CharTy))203 Result.getArrayInitializedElt(I) = *ElemVal;204 else205 return false;206 }207 } else {208 assert((std::is_same_v<ResultT, std::string>));209 if (Size < Result.max_size())210 Result.resize(Size);211 Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);212 }213 214 return true;215 });216 217 if (PtrRes.isInvalid()) {218 C.cleanup();219 Stk.clear();220 return false;221 }222 223 return true;224}225 226bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,227 const Expr *PtrExpr, APValue &Result) {228 assert(SizeExpr);229 assert(PtrExpr);230 231 return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);232}233 234bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,235 const Expr *PtrExpr, std::string &Result) {236 assert(SizeExpr);237 assert(PtrExpr);238 239 return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);240}241 242bool Context::evaluateString(State &Parent, const Expr *E,243 std::string &Result) {244 assert(Stk.empty());245 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);246 247 auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {248 const Descriptor *FieldDesc = Ptr.getFieldDesc();249 if (!FieldDesc->isPrimitiveArray())250 return false;251 252 if (!Ptr.isConst())253 return false;254 255 unsigned N = Ptr.getNumElems();256 257 if (Ptr.elemSize() == 1 /* bytes */) {258 const char *Chars = reinterpret_cast<const char *>(Ptr.getRawAddress());259 unsigned Length = strnlen(Chars, N);260 // Wasn't null terminated.261 if (N == Length)262 return false;263 Result.assign(Chars, Length);264 return true;265 }266 267 PrimType ElemT = FieldDesc->getPrimType();268 for (unsigned I = Ptr.getIndex(); I != N; ++I) {269 INT_TYPE_SWITCH(ElemT, {270 auto Elem = Ptr.elem<T>(I);271 if (Elem.isZero())272 return true;273 Result.push_back(static_cast<char>(Elem));274 });275 }276 // We didn't find a 0 byte.277 return false;278 });279 280 if (PtrRes.isInvalid()) {281 C.cleanup();282 Stk.clear();283 return false;284 }285 return true;286}287 288bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) {289 assert(Stk.empty());290 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);291 292 auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) {293 const Descriptor *FieldDesc = Ptr.getFieldDesc();294 if (!FieldDesc->isPrimitiveArray())295 return false;296 297 if (Ptr.isDummy() || Ptr.isUnknownSizeArray())298 return false;299 300 unsigned N = Ptr.getNumElems();301 if (Ptr.elemSize() == 1) {302 Result = strnlen(reinterpret_cast<const char *>(Ptr.getRawAddress()), N);303 return Result != N;304 }305 306 PrimType ElemT = FieldDesc->getPrimType();307 Result = 0;308 for (unsigned I = Ptr.getIndex(); I != N; ++I) {309 INT_TYPE_SWITCH(ElemT, {310 auto Elem = Ptr.elem<T>(I);311 if (Elem.isZero())312 return true;313 ++Result;314 });315 }316 // We didn't find a 0 byte.317 return false;318 });319 320 if (PtrRes.isInvalid()) {321 C.cleanup();322 Stk.clear();323 return false;324 }325 return true;326}327 328const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }329 330static PrimType integralTypeToPrimTypeS(unsigned BitWidth) {331 switch (BitWidth) {332 case 64:333 return PT_Sint64;334 case 32:335 return PT_Sint32;336 case 16:337 return PT_Sint16;338 case 8:339 return PT_Sint8;340 default:341 return PT_IntAPS;342 }343 llvm_unreachable("Unhandled BitWidth");344}345 346static PrimType integralTypeToPrimTypeU(unsigned BitWidth) {347 switch (BitWidth) {348 case 64:349 return PT_Uint64;350 case 32:351 return PT_Uint32;352 case 16:353 return PT_Uint16;354 case 8:355 return PT_Uint8;356 default:357 return PT_IntAP;358 }359 llvm_unreachable("Unhandled BitWidth");360}361 362OptPrimType Context::classify(QualType T) const {363 364 if (const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType())) {365 auto Kind = BT->getKind();366 if (Kind == BuiltinType::Bool)367 return PT_Bool;368 if (Kind == BuiltinType::NullPtr)369 return PT_Ptr;370 if (Kind == BuiltinType::BoundMember)371 return PT_MemberPtr;372 373 // Just trying to avoid the ASTContext::getIntWidth call below.374 if (Kind == BuiltinType::Short)375 return integralTypeToPrimTypeS(this->ShortWidth);376 if (Kind == BuiltinType::UShort)377 return integralTypeToPrimTypeU(this->ShortWidth);378 379 if (Kind == BuiltinType::Int)380 return integralTypeToPrimTypeS(this->IntWidth);381 if (Kind == BuiltinType::UInt)382 return integralTypeToPrimTypeU(this->IntWidth);383 if (Kind == BuiltinType::Long)384 return integralTypeToPrimTypeS(this->LongWidth);385 if (Kind == BuiltinType::ULong)386 return integralTypeToPrimTypeU(this->LongWidth);387 if (Kind == BuiltinType::LongLong)388 return integralTypeToPrimTypeS(this->LongLongWidth);389 if (Kind == BuiltinType::ULongLong)390 return integralTypeToPrimTypeU(this->LongLongWidth);391 392 if (Kind == BuiltinType::SChar || Kind == BuiltinType::Char_S)393 return integralTypeToPrimTypeS(8);394 if (Kind == BuiltinType::UChar || Kind == BuiltinType::Char_U ||395 Kind == BuiltinType::Char8)396 return integralTypeToPrimTypeU(8);397 398 if (BT->isSignedInteger())399 return integralTypeToPrimTypeS(Ctx.getIntWidth(T));400 if (BT->isUnsignedInteger())401 return integralTypeToPrimTypeU(Ctx.getIntWidth(T));402 403 if (BT->isFloatingPoint())404 return PT_Float;405 }406 407 if (T->isPointerOrReferenceType())408 return PT_Ptr;409 410 if (T->isMemberPointerType())411 return PT_MemberPtr;412 413 if (const auto *BT = T->getAs<BitIntType>()) {414 if (BT->isSigned())415 return integralTypeToPrimTypeS(BT->getNumBits());416 return integralTypeToPrimTypeU(BT->getNumBits());417 }418 419 if (const auto *D = T->getAsEnumDecl()) {420 if (!D->isComplete())421 return std::nullopt;422 return classify(D->getIntegerType());423 }424 425 if (const auto *AT = T->getAs<AtomicType>())426 return classify(AT->getValueType());427 428 if (const auto *DT = dyn_cast<DecltypeType>(T))429 return classify(DT->getUnderlyingType());430 431 if (T->isObjCObjectPointerType() || T->isBlockPointerType())432 return PT_Ptr;433 434 if (T->isFixedPointType())435 return PT_FixedPoint;436 437 // Vector and complex types get here.438 return std::nullopt;439}440 441unsigned Context::getCharBit() const {442 return Ctx.getTargetInfo().getCharWidth();443}444 445/// Simple wrapper around getFloatTypeSemantics() to make code a446/// little shorter.447const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {448 return Ctx.getFloatTypeSemantics(T);449}450 451bool Context::Run(State &Parent, const Function *Func) {452 InterpState State(Parent, *P, Stk, *this, Func);453 if (Interpret(State)) {454 assert(Stk.empty());455 return true;456 }457 Stk.clear();458 return false;459}460 461// TODO: Virtual bases?462const CXXMethodDecl *463Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,464 const CXXRecordDecl *StaticDecl,465 const CXXMethodDecl *InitialFunction) const {466 assert(DynamicDecl);467 assert(StaticDecl);468 assert(InitialFunction);469 470 const CXXRecordDecl *CurRecord = DynamicDecl;471 const CXXMethodDecl *FoundFunction = InitialFunction;472 for (;;) {473 const CXXMethodDecl *Overrider =474 FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);475 if (Overrider)476 return Overrider;477 478 // Common case of only one base class.479 if (CurRecord->getNumBases() == 1) {480 CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();481 continue;482 }483 484 // Otherwise, go to the base class that will lead to the StaticDecl.485 for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {486 const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();487 if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {488 CurRecord = Base;489 break;490 }491 }492 }493 494 llvm_unreachable(495 "Couldn't find an overriding function in the class hierarchy?");496 return nullptr;497}498 499const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) {500 assert(FuncDecl);501 if (const Function *Func = P->getFunction(FuncDecl))502 return Func;503 504 // Manually created functions that haven't been assigned proper505 // parameters yet.506 if (!FuncDecl->param_empty() && !FuncDecl->param_begin())507 return nullptr;508 509 bool IsLambdaStaticInvoker = false;510 if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);511 MD && MD->isLambdaStaticInvoker()) {512 // For a lambda static invoker, we might have to pick a specialized513 // version if the lambda is generic. In that case, the picked function514 // will *NOT* be a static invoker anymore. However, it will still515 // be a non-static member function, this (usually) requiring an516 // instance pointer. We suppress that later in this function.517 IsLambdaStaticInvoker = true;518 }519 // Set up argument indices.520 unsigned ParamOffset = 0;521 SmallVector<PrimType, 8> ParamTypes;522 SmallVector<unsigned, 8> ParamOffsets;523 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;524 525 // If the return is not a primitive, a pointer to the storage where the526 // value is initialized in is passed as the first argument. See 'RVO'527 // elsewhere in the code.528 QualType Ty = FuncDecl->getReturnType();529 bool HasRVO = false;530 if (!Ty->isVoidType() && !canClassify(Ty)) {531 HasRVO = true;532 ParamTypes.push_back(PT_Ptr);533 ParamOffsets.push_back(ParamOffset);534 ParamOffset += align(primSize(PT_Ptr));535 }536 537 // If the function decl is a member decl, the next parameter is538 // the 'this' pointer. This parameter is pop()ed from the539 // InterpStack when calling the function.540 bool HasThisPointer = false;541 if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {542 if (!IsLambdaStaticInvoker) {543 HasThisPointer = MD->isInstance();544 if (MD->isImplicitObjectMemberFunction()) {545 ParamTypes.push_back(PT_Ptr);546 ParamOffsets.push_back(ParamOffset);547 ParamOffset += align(primSize(PT_Ptr));548 }549 }550 551 if (isLambdaCallOperator(MD)) {552 // The parent record needs to be complete, we need to know about all553 // the lambda captures.554 if (!MD->getParent()->isCompleteDefinition())555 return nullptr;556 llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;557 FieldDecl *LTC;558 559 MD->getParent()->getCaptureFields(LC, LTC);560 561 if (MD->isStatic() && !LC.empty()) {562 // Static lambdas cannot have any captures. If this one does,563 // it has already been diagnosed and we can only ignore it.564 return nullptr;565 }566 }567 }568 569 // Assign descriptors to all parameters.570 // Composite objects are lowered to pointers.571 const auto *FuncProto = FuncDecl->getType()->getAs<FunctionProtoType>();572 for (auto [ParamIndex, PD] : llvm::enumerate(FuncDecl->parameters())) {573 bool IsConst = PD->getType().isConstQualified();574 bool IsVolatile = PD->getType().isVolatileQualified();575 576 if (!getASTContext().hasSameType(PD->getType(),577 FuncProto->getParamType(ParamIndex)))578 return nullptr;579 580 OptPrimType T = classify(PD->getType());581 PrimType PT = T.value_or(PT_Ptr);582 Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,583 IsConst, /*IsTemporary=*/false,584 /*IsMutable=*/false, IsVolatile);585 586 ParamDescriptors.insert({ParamOffset, {PT, Desc}});587 ParamOffsets.push_back(ParamOffset);588 ParamOffset += align(primSize(PT));589 ParamTypes.push_back(PT);590 }591 592 // Create a handle over the emitted code.593 assert(!P->getFunction(FuncDecl));594 const Function *Func = P->createFunction(595 FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors),596 std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker);597 return Func;598}599 600const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) {601 const BlockDecl *BD = E->getBlockDecl();602 // Set up argument indices.603 unsigned ParamOffset = 0;604 SmallVector<PrimType, 8> ParamTypes;605 SmallVector<unsigned, 8> ParamOffsets;606 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;607 608 // Assign descriptors to all parameters.609 // Composite objects are lowered to pointers.610 for (const ParmVarDecl *PD : BD->parameters()) {611 bool IsConst = PD->getType().isConstQualified();612 bool IsVolatile = PD->getType().isVolatileQualified();613 614 OptPrimType T = classify(PD->getType());615 PrimType PT = T.value_or(PT_Ptr);616 Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt,617 IsConst, /*IsTemporary=*/false,618 /*IsMutable=*/false, IsVolatile);619 ParamDescriptors.insert({ParamOffset, {PT, Desc}});620 ParamOffsets.push_back(ParamOffset);621 ParamOffset += align(primSize(PT));622 ParamTypes.push_back(PT);623 }624 625 if (BD->hasCaptures())626 return nullptr;627 628 // Create a handle over the emitted code.629 Function *Func =630 P->createFunction(E, ParamOffset, std::move(ParamTypes),631 std::move(ParamDescriptors), std::move(ParamOffsets),632 /*HasThisPointer=*/false, /*HasRVO=*/false,633 /*IsLambdaStaticInvoker=*/false);634 635 assert(Func);636 Func->setDefined(true);637 // We don't compile the BlockDecl code at all right now.638 Func->setIsFullyCompiled(true);639 return Func;640}641 642unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,643 const RecordDecl *DerivedDecl) const {644 assert(BaseDecl);645 assert(DerivedDecl);646 const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);647 const RecordDecl *CurDecl = DerivedDecl;648 const Record *CurRecord = P->getOrCreateRecord(CurDecl);649 assert(CurDecl && FinalDecl);650 651 unsigned OffsetSum = 0;652 for (;;) {653 assert(CurRecord->getNumBases() > 0);654 // One level up655 for (const Record::Base &B : CurRecord->bases()) {656 const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);657 658 if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {659 OffsetSum += B.Offset;660 CurRecord = B.R;661 CurDecl = BaseDecl;662 break;663 }664 }665 if (CurDecl == FinalDecl)666 break;667 }668 669 assert(OffsetSum > 0);670 return OffsetSum;671}672 673const Record *Context::getRecord(const RecordDecl *D) const {674 return P->getOrCreateRecord(D);675}676 677bool Context::isUnevaluatedBuiltin(unsigned ID) {678 return ID == Builtin::BI__builtin_classify_type ||679 ID == Builtin::BI__builtin_os_log_format_buffer_size ||680 ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;681}682