Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Context.cpp
213799 views
//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Context.h"9#include "ByteCodeEmitter.h"10#include "Compiler.h"11#include "EvalEmitter.h"12#include "Interp.h"13#include "InterpFrame.h"14#include "InterpStack.h"15#include "PrimType.h"16#include "Program.h"17#include "clang/AST/Expr.h"18#include "clang/Basic/TargetInfo.h"1920using namespace clang;21using namespace clang::interp;2223Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {24this->ShortWidth = Ctx.getTargetInfo().getShortWidth();25this->IntWidth = Ctx.getTargetInfo().getIntWidth();26this->LongWidth = Ctx.getTargetInfo().getLongWidth();27this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();28assert(Ctx.getTargetInfo().getCharWidth() == 8 &&29"We're assuming 8 bit chars");30}3132Context::~Context() {}3334bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {35assert(Stk.empty());3637// Get a function handle.38const Function *Func = getOrCreateFunction(FD);39if (!Func)40return false;4142// Compile the function.43Compiler<ByteCodeEmitter>(*this, *P).compileFunc(44FD, const_cast<Function *>(Func));4546++EvalID;47// And run it.48if (!Run(Parent, Func))49return false;5051return Func->isValid();52}5354bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {55++EvalID;56bool Recursing = !Stk.empty();57size_t StackSizeBefore = Stk.size();58Compiler<EvalEmitter> C(*this, *P, Parent, Stk);5960auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());6162if (Res.isInvalid()) {63C.cleanup();64Stk.clearTo(StackSizeBefore);65return false;66}6768if (!Recursing) {69// We *can* actually get here with a non-empty stack, since70// things like InterpState::noteSideEffect() exist.71C.cleanup();72#ifndef NDEBUG73// Make sure we don't rely on some value being still alive in74// InterpStack memory.75Stk.clearTo(StackSizeBefore);76#endif77}7879Result = Res.toAPValue();8081return true;82}8384bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,85ConstantExprKind Kind) {86++EvalID;87bool Recursing = !Stk.empty();88size_t StackSizeBefore = Stk.size();89Compiler<EvalEmitter> C(*this, *P, Parent, Stk);9091auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,92/*DestroyToplevelScope=*/true);93if (Res.isInvalid()) {94C.cleanup();95Stk.clearTo(StackSizeBefore);96return false;97}9899if (!Recursing) {100assert(Stk.empty());101C.cleanup();102#ifndef NDEBUG103// Make sure we don't rely on some value being still alive in104// InterpStack memory.105Stk.clearTo(StackSizeBefore);106#endif107}108109Result = Res.toAPValue();110return true;111}112113bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,114APValue &Result) {115++EvalID;116bool Recursing = !Stk.empty();117size_t StackSizeBefore = Stk.size();118Compiler<EvalEmitter> C(*this, *P, Parent, Stk);119120bool CheckGlobalInitialized =121shouldBeGloballyIndexed(VD) &&122(VD->getType()->isRecordType() || VD->getType()->isArrayType());123auto Res = C.interpretDecl(VD, CheckGlobalInitialized);124if (Res.isInvalid()) {125C.cleanup();126Stk.clearTo(StackSizeBefore);127128return false;129}130131if (!Recursing) {132assert(Stk.empty());133C.cleanup();134#ifndef NDEBUG135// Make sure we don't rely on some value being still alive in136// InterpStack memory.137Stk.clearTo(StackSizeBefore);138#endif139}140141Result = Res.toAPValue();142return true;143}144145template <typename ResultT>146bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,147const Expr *PtrExpr, ResultT &Result) {148assert(Stk.empty());149Compiler<EvalEmitter> C(*this, *P, Parent, Stk);150151// Evaluate size value.152APValue SizeValue;153if (!evaluateAsRValue(Parent, SizeExpr, SizeValue))154return false;155156if (!SizeValue.isInt())157return false;158uint64_t Size = SizeValue.getInt().getZExtValue();159160auto PtrRes = C.interpretAsPointer(PtrExpr, [&](const Pointer &Ptr) {161if (Size == 0) {162if constexpr (std::is_same_v<ResultT, APValue>)163Result = APValue(APValue::UninitArray{}, 0, 0);164return true;165}166167if (!Ptr.isLive() || !Ptr.getFieldDesc()->isPrimitiveArray())168return false;169170// Must be char.171if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/)172return false;173174if (Size > Ptr.getNumElems()) {175Parent.FFDiag(SizeExpr, diag::note_constexpr_access_past_end) << AK_Read;176Size = Ptr.getNumElems();177}178179if constexpr (std::is_same_v<ResultT, APValue>) {180QualType CharTy = PtrExpr->getType()->getPointeeType();181Result = APValue(APValue::UninitArray{}, Size, Size);182for (uint64_t I = 0; I != Size; ++I) {183if (std::optional<APValue> ElemVal =184Ptr.atIndex(I).toRValue(*this, CharTy))185Result.getArrayInitializedElt(I) = *ElemVal;186else187return false;188}189} else {190assert((std::is_same_v<ResultT, std::string>));191if (Size < Result.max_size())192Result.resize(Size);193Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);194}195196return true;197});198199if (PtrRes.isInvalid()) {200C.cleanup();201Stk.clear();202return false;203}204205return true;206}207208bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,209const Expr *PtrExpr, APValue &Result) {210assert(SizeExpr);211assert(PtrExpr);212213return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);214}215216bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,217const Expr *PtrExpr, std::string &Result) {218assert(SizeExpr);219assert(PtrExpr);220221return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);222}223224const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }225226static PrimType integralTypeToPrimTypeS(unsigned BitWidth) {227switch (BitWidth) {228case 64:229return PT_Sint64;230case 32:231return PT_Sint32;232case 16:233return PT_Sint16;234case 8:235return PT_Sint8;236default:237return PT_IntAPS;238}239llvm_unreachable("Unhandled BitWidth");240}241242static PrimType integralTypeToPrimTypeU(unsigned BitWidth) {243switch (BitWidth) {244case 64:245return PT_Uint64;246case 32:247return PT_Uint32;248case 16:249return PT_Uint16;250case 8:251return PT_Uint8;252default:253return PT_IntAP;254}255llvm_unreachable("Unhandled BitWidth");256}257258std::optional<PrimType> Context::classify(QualType T) const {259260if (const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType())) {261auto Kind = BT->getKind();262if (Kind == BuiltinType::Bool)263return PT_Bool;264if (Kind == BuiltinType::NullPtr)265return PT_Ptr;266if (Kind == BuiltinType::BoundMember)267return PT_MemberPtr;268269// Just trying to avoid the ASTContext::getIntWidth call below.270if (Kind == BuiltinType::Short)271return integralTypeToPrimTypeS(this->ShortWidth);272if (Kind == BuiltinType::UShort)273return integralTypeToPrimTypeU(this->ShortWidth);274275if (Kind == BuiltinType::Int)276return integralTypeToPrimTypeS(this->IntWidth);277if (Kind == BuiltinType::UInt)278return integralTypeToPrimTypeU(this->IntWidth);279if (Kind == BuiltinType::Long)280return integralTypeToPrimTypeS(this->LongWidth);281if (Kind == BuiltinType::ULong)282return integralTypeToPrimTypeU(this->LongWidth);283if (Kind == BuiltinType::LongLong)284return integralTypeToPrimTypeS(this->LongLongWidth);285if (Kind == BuiltinType::ULongLong)286return integralTypeToPrimTypeU(this->LongLongWidth);287288if (Kind == BuiltinType::SChar || Kind == BuiltinType::Char_S)289return integralTypeToPrimTypeS(8);290if (Kind == BuiltinType::UChar || Kind == BuiltinType::Char_U ||291Kind == BuiltinType::Char8)292return integralTypeToPrimTypeU(8);293294if (BT->isSignedInteger())295return integralTypeToPrimTypeS(Ctx.getIntWidth(T));296if (BT->isUnsignedInteger())297return integralTypeToPrimTypeU(Ctx.getIntWidth(T));298299if (BT->isFloatingPoint())300return PT_Float;301}302303if (T->isPointerOrReferenceType())304return PT_Ptr;305306if (T->isMemberPointerType())307return PT_MemberPtr;308309if (const auto *BT = T->getAs<BitIntType>()) {310if (BT->isSigned())311return integralTypeToPrimTypeS(BT->getNumBits());312return integralTypeToPrimTypeU(BT->getNumBits());313}314315if (const auto *ET = T->getAs<EnumType>()) {316const auto *D = ET->getDecl();317if (!D->isComplete())318return std::nullopt;319return classify(D->getIntegerType());320}321322if (const auto *AT = T->getAs<AtomicType>())323return classify(AT->getValueType());324325if (const auto *DT = dyn_cast<DecltypeType>(T))326return classify(DT->getUnderlyingType());327328if (T->isObjCObjectPointerType() || T->isBlockPointerType())329return PT_Ptr;330331if (T->isFixedPointType())332return PT_FixedPoint;333334// Vector and complex types get here.335return std::nullopt;336}337338unsigned Context::getCharBit() const {339return Ctx.getTargetInfo().getCharWidth();340}341342/// Simple wrapper around getFloatTypeSemantics() to make code a343/// little shorter.344const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {345return Ctx.getFloatTypeSemantics(T);346}347348bool Context::Run(State &Parent, const Function *Func) {349350{351InterpState State(Parent, *P, Stk, *this, Func);352if (Interpret(State)) {353assert(Stk.empty());354return true;355}356// State gets destroyed here, so the Stk.clear() below doesn't accidentally357// remove values the State's destructor might access.358}359360Stk.clear();361return false;362}363364// TODO: Virtual bases?365const CXXMethodDecl *366Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,367const CXXRecordDecl *StaticDecl,368const CXXMethodDecl *InitialFunction) const {369assert(DynamicDecl);370assert(StaticDecl);371assert(InitialFunction);372373const CXXRecordDecl *CurRecord = DynamicDecl;374const CXXMethodDecl *FoundFunction = InitialFunction;375for (;;) {376const CXXMethodDecl *Overrider =377FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);378if (Overrider)379return Overrider;380381// Common case of only one base class.382if (CurRecord->getNumBases() == 1) {383CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();384continue;385}386387// Otherwise, go to the base class that will lead to the StaticDecl.388for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {389const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();390if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {391CurRecord = Base;392break;393}394}395}396397llvm_unreachable(398"Couldn't find an overriding function in the class hierarchy?");399return nullptr;400}401402const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) {403assert(FuncDecl);404FuncDecl = FuncDecl->getMostRecentDecl();405406if (const Function *Func = P->getFunction(FuncDecl))407return Func;408409// Manually created functions that haven't been assigned proper410// parameters yet.411if (!FuncDecl->param_empty() && !FuncDecl->param_begin())412return nullptr;413414bool IsLambdaStaticInvoker = false;415if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);416MD && MD->isLambdaStaticInvoker()) {417// For a lambda static invoker, we might have to pick a specialized418// version if the lambda is generic. In that case, the picked function419// will *NOT* be a static invoker anymore. However, it will still420// be a non-static member function, this (usually) requiring an421// instance pointer. We suppress that later in this function.422IsLambdaStaticInvoker = true;423424const CXXRecordDecl *ClosureClass = MD->getParent();425assert(ClosureClass->captures_begin() == ClosureClass->captures_end());426if (ClosureClass->isGenericLambda()) {427const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator();428assert(MD->isFunctionTemplateSpecialization() &&429"A generic lambda's static-invoker function must be a "430"template specialization");431const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();432FunctionTemplateDecl *CallOpTemplate =433LambdaCallOp->getDescribedFunctionTemplate();434void *InsertPos = nullptr;435const FunctionDecl *CorrespondingCallOpSpecialization =436CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);437assert(CorrespondingCallOpSpecialization);438FuncDecl = CorrespondingCallOpSpecialization;439}440}441// Set up argument indices.442unsigned ParamOffset = 0;443SmallVector<PrimType, 8> ParamTypes;444SmallVector<unsigned, 8> ParamOffsets;445llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;446447// If the return is not a primitive, a pointer to the storage where the448// value is initialized in is passed as the first argument. See 'RVO'449// elsewhere in the code.450QualType Ty = FuncDecl->getReturnType();451bool HasRVO = false;452if (!Ty->isVoidType() && !classify(Ty)) {453HasRVO = true;454ParamTypes.push_back(PT_Ptr);455ParamOffsets.push_back(ParamOffset);456ParamOffset += align(primSize(PT_Ptr));457}458459// If the function decl is a member decl, the next parameter is460// the 'this' pointer. This parameter is pop()ed from the461// InterpStack when calling the function.462bool HasThisPointer = false;463if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {464if (!IsLambdaStaticInvoker) {465HasThisPointer = MD->isInstance();466if (MD->isImplicitObjectMemberFunction()) {467ParamTypes.push_back(PT_Ptr);468ParamOffsets.push_back(ParamOffset);469ParamOffset += align(primSize(PT_Ptr));470}471}472473if (isLambdaCallOperator(MD)) {474// The parent record needs to be complete, we need to know about all475// the lambda captures.476if (!MD->getParent()->isCompleteDefinition())477return nullptr;478llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;479FieldDecl *LTC;480481MD->getParent()->getCaptureFields(LC, LTC);482483if (MD->isStatic() && !LC.empty()) {484// Static lambdas cannot have any captures. If this one does,485// it has already been diagnosed and we can only ignore it.486return nullptr;487}488}489}490491// Assign descriptors to all parameters.492// Composite objects are lowered to pointers.493for (const ParmVarDecl *PD : FuncDecl->parameters()) {494std::optional<PrimType> T = classify(PD->getType());495PrimType PT = T.value_or(PT_Ptr);496Descriptor *Desc = P->createDescriptor(PD, PT);497ParamDescriptors.insert({ParamOffset, {PT, Desc}});498ParamOffsets.push_back(ParamOffset);499ParamOffset += align(primSize(PT));500ParamTypes.push_back(PT);501}502503// Create a handle over the emitted code.504assert(!P->getFunction(FuncDecl));505const Function *Func = P->createFunction(506FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors),507std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker);508return Func;509}510511const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) {512const BlockDecl *BD = E->getBlockDecl();513// Set up argument indices.514unsigned ParamOffset = 0;515SmallVector<PrimType, 8> ParamTypes;516SmallVector<unsigned, 8> ParamOffsets;517llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;518519// Assign descriptors to all parameters.520// Composite objects are lowered to pointers.521for (const ParmVarDecl *PD : BD->parameters()) {522std::optional<PrimType> T = classify(PD->getType());523PrimType PT = T.value_or(PT_Ptr);524Descriptor *Desc = P->createDescriptor(PD, PT);525ParamDescriptors.insert({ParamOffset, {PT, Desc}});526ParamOffsets.push_back(ParamOffset);527ParamOffset += align(primSize(PT));528ParamTypes.push_back(PT);529}530531if (BD->hasCaptures())532return nullptr;533534// Create a handle over the emitted code.535Function *Func =536P->createFunction(E, ParamOffset, std::move(ParamTypes),537std::move(ParamDescriptors), std::move(ParamOffsets),538/*HasThisPointer=*/false, /*HasRVO=*/false,539/*IsLambdaStaticInvoker=*/false);540541assert(Func);542Func->setDefined(true);543// We don't compile the BlockDecl code at all right now.544Func->setIsFullyCompiled(true);545return Func;546}547548unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,549const RecordDecl *DerivedDecl) const {550assert(BaseDecl);551assert(DerivedDecl);552const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);553const RecordDecl *CurDecl = DerivedDecl;554const Record *CurRecord = P->getOrCreateRecord(CurDecl);555assert(CurDecl && FinalDecl);556557unsigned OffsetSum = 0;558for (;;) {559assert(CurRecord->getNumBases() > 0);560// One level up561for (const Record::Base &B : CurRecord->bases()) {562const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);563564if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {565OffsetSum += B.Offset;566CurRecord = B.R;567CurDecl = BaseDecl;568break;569}570}571if (CurDecl == FinalDecl)572break;573}574575assert(OffsetSum > 0);576return OffsetSum;577}578579const Record *Context::getRecord(const RecordDecl *D) const {580return P->getOrCreateRecord(D);581}582583bool Context::isUnevaluatedBuiltin(unsigned ID) {584return ID == Builtin::BI__builtin_classify_type ||585ID == Builtin::BI__builtin_os_log_format_buffer_size ||586ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;587}588589590