739 lines · cpp
1//===--- InterpreterValuePrinter.cpp - Value printing utils -----*- 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// This file implements routines for in-process value printing in clang-repl.10//11//===----------------------------------------------------------------------===//12 13#include "IncrementalAction.h"14#include "InterpreterUtils.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/PrettyPrinter.h"17#include "clang/AST/Type.h"18#include "clang/Frontend/CompilerInstance.h"19#include "clang/Interpreter/Interpreter.h"20#include "clang/Interpreter/Value.h"21#include "clang/Lex/Preprocessor.h"22#include "clang/Sema/Lookup.h"23#include "clang/Sema/Sema.h"24 25#include "llvm/Support/Error.h"26#include "llvm/Support/raw_ostream.h"27 28#include <cassert>29#include <cmath>30#include <cstdarg>31#include <sstream>32#include <string>33 34#define DEBUG_TYPE "interp-value"35 36using namespace clang;37 38static std::string DeclTypeToString(const QualType &QT, NamedDecl *D) {39 std::string Str;40 llvm::raw_string_ostream SS(Str);41 if (QT.hasQualifiers())42 SS << QT.getQualifiers().getAsString() << " ";43 SS << D->getQualifiedNameAsString();44 return Str;45}46 47static std::string QualTypeToString(ASTContext &Ctx, QualType QT) {48 PrintingPolicy Policy(Ctx.getPrintingPolicy());49 // Print the Allocator in STL containers, for instance.50 Policy.SuppressDefaultTemplateArgs = false;51 Policy.SuppressUnwrittenScope = true;52 // Print 'a<b<c> >' rather than 'a<b<c>>'.53 Policy.SplitTemplateClosers = true;54 55 struct LocalPrintingPolicyRAII {56 ASTContext &Context;57 PrintingPolicy Policy;58 59 LocalPrintingPolicyRAII(ASTContext &Ctx, PrintingPolicy &PP)60 : Context(Ctx), Policy(Ctx.getPrintingPolicy()) {61 Context.setPrintingPolicy(PP);62 }63 ~LocalPrintingPolicyRAII() { Context.setPrintingPolicy(Policy); }64 } X(Ctx, Policy);65 66 const QualType NonRefTy = QT.getNonReferenceType();67 68 if (const auto *TTy = llvm::dyn_cast<TagType>(NonRefTy))69 return DeclTypeToString(NonRefTy, TTy->getDecl());70 71 if (const auto *TRy = dyn_cast<RecordType>(NonRefTy))72 return DeclTypeToString(NonRefTy, TRy->getDecl());73 74 const QualType Canon = NonRefTy.getCanonicalType();75 76 // FIXME: How a builtin type can be a function pointer type?77 if (Canon->isBuiltinType() && !NonRefTy->isFunctionPointerType() &&78 !NonRefTy->isMemberPointerType())79 return Canon.getAsString(Ctx.getPrintingPolicy());80 81 if (const auto *TDTy = dyn_cast<TypedefType>(NonRefTy)) {82 // FIXME: TemplateSpecializationType & SubstTemplateTypeParmType checks83 // are predominately to get STL containers to print nicer and might be84 // better handled in GetFullyQualifiedName.85 //86 // std::vector<Type>::iterator is a TemplateSpecializationType87 // std::vector<Type>::value_type is a SubstTemplateTypeParmType88 //89 QualType SSDesugar = TDTy->getLocallyUnqualifiedSingleStepDesugaredType();90 if (llvm::isa<SubstTemplateTypeParmType>(SSDesugar))91 return GetFullTypeName(Ctx, Canon);92 else if (llvm::isa<TemplateSpecializationType>(SSDesugar))93 return GetFullTypeName(Ctx, NonRefTy);94 return DeclTypeToString(NonRefTy, TDTy->getDecl());95 }96 return GetFullTypeName(Ctx, NonRefTy);97}98 99static std::string EnumToString(const Value &V) {100 std::string Str;101 llvm::raw_string_ostream SS(Str);102 ASTContext &Ctx = const_cast<ASTContext &>(V.getASTContext());103 104 uint64_t Data = V.convertTo<uint64_t>();105 bool IsFirst = true;106 llvm::APSInt AP = Ctx.MakeIntValue(Data, V.getType());107 108 auto *ED = V.getType()->castAsEnumDecl();109 for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) {110 if (I->getInitVal() == AP) {111 if (!IsFirst)112 SS << " ? ";113 SS << "(" + I->getQualifiedNameAsString() << ")";114 IsFirst = false;115 }116 }117 llvm::SmallString<64> APStr;118 AP.toString(APStr, /*Radix=*/10);119 SS << " : " << QualTypeToString(Ctx, ED->getIntegerType()) << " " << APStr;120 return Str;121}122 123static std::string FunctionToString(const Value &V, const void *Ptr) {124 std::string Str;125 llvm::raw_string_ostream SS(Str);126 SS << "Function @" << Ptr;127 128 const DeclContext *PTU = V.getASTContext().getTranslationUnitDecl();129 // Find the last top-level-stmt-decl. This is a forward iterator but the130 // partial translation unit should not be large.131 const TopLevelStmtDecl *TLSD = nullptr;132 for (const Decl *D : PTU->noload_decls())133 if (isa<TopLevelStmtDecl>(D))134 TLSD = cast<TopLevelStmtDecl>(D);135 136 // Get __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void137 // *OpaqueType, void *Val);138 const FunctionDecl *FD = nullptr;139 if (auto *InterfaceCall = llvm::dyn_cast<CallExpr>(TLSD->getStmt())) {140 const auto *Arg = InterfaceCall->getArg(/*Val*/ 3);141 // Get rid of cast nodes.142 while (const CastExpr *CastE = llvm::dyn_cast<CastExpr>(Arg))143 Arg = CastE->getSubExpr();144 if (const DeclRefExpr *DeclRefExp = llvm::dyn_cast<DeclRefExpr>(Arg))145 FD = llvm::dyn_cast<FunctionDecl>(DeclRefExp->getDecl());146 147 if (FD) {148 SS << '\n';149 const clang::FunctionDecl *FDef;150 if (FD->hasBody(FDef))151 FDef->print(SS);152 }153 }154 return Str;155}156 157static std::string VoidPtrToString(const void *Ptr) {158 std::string Str;159 llvm::raw_string_ostream SS(Str);160 SS << Ptr;161 return Str;162}163 164static std::string CharPtrToString(const char *Ptr) {165 if (!Ptr)166 return "0";167 168 std::string Result = "\"";169 Result += Ptr;170 Result += '"';171 return Result;172}173 174namespace clang {175 176struct ValueRef : public Value {177 ValueRef(const Interpreter *In, void *Ty) : Value(In, Ty) {178 // Tell the base class to not try to deallocate if it manages the value.179 IsManuallyAlloc = false;180 }181};182 183std::string Interpreter::ValueDataToString(const Value &V) const {184 Sema &S = getCompilerInstance()->getSema();185 ASTContext &Ctx = S.getASTContext();186 187 QualType QT = V.getType();188 189 if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(QT)) {190 QualType ElemTy = CAT->getElementType();191 size_t ElemCount = Ctx.getConstantArrayElementCount(CAT);192 const Type *BaseTy = CAT->getBaseElementTypeUnsafe();193 size_t ElemSize = Ctx.getTypeSizeInChars(BaseTy).getQuantity();194 195 // Treat null terminated char arrays as strings basically.196 if (ElemTy->isCharType()) {197 char last = *(char *)(((uintptr_t)V.getPtr()) + ElemCount * ElemSize - 1);198 if (last == '\0')199 return CharPtrToString((char *)V.getPtr());200 }201 202 std::string Result = "{ ";203 for (unsigned Idx = 0, N = CAT->getZExtSize(); Idx < N; ++Idx) {204 ValueRef InnerV = ValueRef(this, ElemTy.getAsOpaquePtr());205 if (ElemTy->isBuiltinType()) {206 // Single dim arrays, advancing.207 uintptr_t Offset = (uintptr_t)V.getPtr() + Idx * ElemSize;208 InnerV.setRawBits((void *)Offset, ElemSize * 8);209 } else {210 // Multi dim arrays, position to the next dimension.211 size_t Stride = ElemCount / N;212 uintptr_t Offset = ((uintptr_t)V.getPtr()) + Idx * Stride * ElemSize;213 InnerV.setPtr((void *)Offset);214 }215 216 Result += ValueDataToString(InnerV);217 218 // Skip the \0 if the char types219 if (Idx < N - 1)220 Result += ", ";221 }222 Result += " }";223 return Result;224 }225 226 QualType DesugaredTy = QT.getDesugaredType(Ctx);227 QualType NonRefTy = DesugaredTy.getNonReferenceType();228 229 // FIXME: Add support for user defined printers.230 // LookupResult R = LookupUserDefined(S, QT);231 // if (!R.empty())232 // return CallUserSpecifiedPrinter(R, V);233 234 // If it is a builtin type dispatch to the builtin overloads.235 if (auto *BT = DesugaredTy.getCanonicalType()->getAs<BuiltinType>()) {236 237 auto formatFloating = [](auto Val, char Suffix = '\0') -> std::string {238 std::string Out;239 llvm::raw_string_ostream SS(Out);240 241 if (std::isnan(Val) || std::isinf(Val)) {242 SS << llvm::format("%g", Val);243 return SS.str();244 }245 if (Val == static_cast<decltype(Val)>(static_cast<int64_t>(Val)))246 SS << llvm::format("%.1f", Val);247 else if (std::abs(Val) < 1e-4 || std::abs(Val) > 1e6 || Suffix == 'f')248 SS << llvm::format("%#.6g", Val);249 else if (Suffix == 'L')250 SS << llvm::format("%#.12Lg", Val);251 else252 SS << llvm::format("%#.8g", Val);253 254 if (Suffix != '\0')255 SS << Suffix;256 return SS.str();257 };258 259 std::string Str;260 llvm::raw_string_ostream SS(Str);261 switch (BT->getKind()) {262 default:263 return "{ error: unknown builtin type '" + std::to_string(BT->getKind()) +264 " '}";265 case clang::BuiltinType::Bool:266 SS << ((V.getBool()) ? "true" : "false");267 return Str;268 case clang::BuiltinType::Char_S:269 SS << '\'' << V.getChar_S() << '\'';270 return Str;271 case clang::BuiltinType::SChar:272 SS << '\'' << V.getSChar() << '\'';273 return Str;274 case clang::BuiltinType::Char_U:275 SS << '\'' << V.getChar_U() << '\'';276 return Str;277 case clang::BuiltinType::UChar:278 SS << '\'' << V.getUChar() << '\'';279 return Str;280 case clang::BuiltinType::Short:281 SS << V.getShort();282 return Str;283 case clang::BuiltinType::UShort:284 SS << V.getUShort();285 return Str;286 case clang::BuiltinType::Int:287 SS << V.getInt();288 return Str;289 case clang::BuiltinType::UInt:290 SS << V.getUInt();291 return Str;292 case clang::BuiltinType::Long:293 SS << V.getLong();294 return Str;295 case clang::BuiltinType::ULong:296 SS << V.getULong();297 return Str;298 case clang::BuiltinType::LongLong:299 SS << V.getLongLong();300 return Str;301 case clang::BuiltinType::ULongLong:302 SS << V.getULongLong();303 return Str;304 case clang::BuiltinType::Float:305 return formatFloating(V.getFloat(), /*suffix=*/'f');306 307 case clang::BuiltinType::Double:308 return formatFloating(V.getDouble());309 310 case clang::BuiltinType::LongDouble:311 return formatFloating(V.getLongDouble(), /*suffix=*/'L');312 }313 }314 315 if ((NonRefTy->isPointerType() || NonRefTy->isMemberPointerType()) &&316 NonRefTy->getPointeeType()->isFunctionProtoType())317 return FunctionToString(V, V.getPtr());318 319 if (NonRefTy->isFunctionType())320 return FunctionToString(V, &V);321 322 if (NonRefTy->isEnumeralType())323 return EnumToString(V);324 325 if (NonRefTy->isNullPtrType())326 return "nullptr\n";327 328 // FIXME: Add support for custom printers in C.329 if (NonRefTy->isPointerType()) {330 if (NonRefTy->getPointeeType()->isCharType())331 return CharPtrToString((char *)V.getPtr());332 333 return VoidPtrToString(V.getPtr());334 }335 336 // Fall back to printing just the address of the unknown object.337 return "@" + VoidPtrToString(V.getPtr());338}339 340std::string Interpreter::ValueTypeToString(const Value &V) const {341 ASTContext &Ctx = const_cast<ASTContext &>(V.getASTContext());342 QualType QT = V.getType();343 344 std::string QTStr = QualTypeToString(Ctx, QT);345 346 if (QT->isReferenceType())347 QTStr += " &";348 349 return QTStr;350}351 352llvm::Expected<llvm::orc::ExecutorAddr>353Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) const {354 assert(CXXRD && "Cannot compile a destructor for a nullptr");355 if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end())356 return Dtor->getSecond();357 358 if (CXXRD->hasIrrelevantDestructor())359 return llvm::orc::ExecutorAddr{};360 361 CXXDestructorDecl *DtorRD =362 getCompilerInstance()->getSema().LookupDestructor(CXXRD);363 364 llvm::StringRef Name =365 Act->getCodeGen()->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));366 auto AddrOrErr = getSymbolAddress(Name);367 if (!AddrOrErr)368 return AddrOrErr.takeError();369 370 Dtors[CXXRD] = *AddrOrErr;371 return AddrOrErr;372}373 374enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };375 376class InterfaceKindVisitor377 : public TypeVisitor<InterfaceKindVisitor, InterfaceKind> {378 379 Sema &S;380 Expr *E;381 llvm::SmallVectorImpl<Expr *> &Args;382 383public:384 InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args)385 : S(S), E(E), Args(Args) {}386 387 InterfaceKind computeInterfaceKind(QualType Ty) {388 return Visit(Ty.getTypePtr());389 }390 391 InterfaceKind VisitRecordType(const RecordType *Ty) {392 return InterfaceKind::WithAlloc;393 }394 395 InterfaceKind VisitMemberPointerType(const MemberPointerType *Ty) {396 return InterfaceKind::WithAlloc;397 }398 399 InterfaceKind VisitConstantArrayType(const ConstantArrayType *Ty) {400 return InterfaceKind::CopyArray;401 }402 403 InterfaceKind VisitFunctionType(const FunctionType *Ty) {404 HandlePtrType(Ty);405 return InterfaceKind::NoAlloc;406 }407 408 InterfaceKind VisitPointerType(const PointerType *Ty) {409 HandlePtrType(Ty);410 return InterfaceKind::NoAlloc;411 }412 413 InterfaceKind VisitReferenceType(const ReferenceType *Ty) {414 ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf,415 E->IgnoreImpCasts());416 assert(!AddrOfE.isInvalid() && "Can not create unary expression");417 Args.push_back(AddrOfE.get());418 return InterfaceKind::NoAlloc;419 }420 421 InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {422 if (Ty->isNullPtrType())423 Args.push_back(E);424 else if (Ty->isFloatingType())425 Args.push_back(E);426 else if (Ty->isIntegralOrEnumerationType())427 HandleIntegralOrEnumType(Ty);428 else if (Ty->isVoidType()) {429 // Do we need to still run `E`?430 }431 432 return InterfaceKind::NoAlloc;433 }434 435 InterfaceKind VisitEnumType(const EnumType *Ty) {436 HandleIntegralOrEnumType(Ty);437 return InterfaceKind::NoAlloc;438 }439 440private:441 // Force cast these types to the uint that fits the register size. That way we442 // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.443 void HandleIntegralOrEnumType(const Type *Ty) {444 ASTContext &Ctx = S.getASTContext();445 uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);446 QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits);447 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy);448 ExprResult CastedExpr =449 S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);450 assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");451 Args.push_back(CastedExpr.get());452 }453 454 void HandlePtrType(const Type *Ty) {455 ASTContext &Ctx = S.getASTContext();456 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);457 ExprResult CastedExpr =458 S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);459 assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");460 Args.push_back(CastedExpr.get());461 }462};463 464static constexpr llvm::StringRef VPName[] = {465 "__clang_Interpreter_SetValueNoAlloc",466 "__clang_Interpreter_SetValueWithAlloc",467 "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};468 469// This synthesizes a call expression to a speciall470// function that is responsible for generating the Value.471// In general, we transform c++:472// clang-repl> x473// To:474// // 1. If x is a built-in type like int, float.475// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);476// // 2. If x is a struct, and a lvalue.477// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,478// &x);479// // 3. If x is a struct, but a rvalue.480// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,481// xQualType)) (x);482llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E) {483 Sema &S = getCompilerInstance()->getSema();484 ASTContext &Ctx = S.getASTContext();485 486 // Find the value printing builtins.487 if (!ValuePrintingInfo[0]) {488 assert(llvm::all_of(ValuePrintingInfo, [](Expr *E) { return !E; }));489 490 auto LookupInterface = [&](Expr *&Interface,491 llvm::StringRef Name) -> llvm::Error {492 LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),493 Sema::LookupOrdinaryName,494 RedeclarationKind::ForVisibleRedeclaration);495 S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());496 if (R.empty())497 return llvm::make_error<llvm::StringError>(498 Name + " not found!", llvm::inconvertibleErrorCode());499 500 CXXScopeSpec CSS;501 Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();502 return llvm::Error::success();503 };504 if (llvm::Error Err =505 LookupInterface(ValuePrintingInfo[NoAlloc], VPName[NoAlloc]))506 return std::move(Err);507 508 if (llvm::Error Err =509 LookupInterface(ValuePrintingInfo[CopyArray], VPName[CopyArray]))510 return std::move(Err);511 512 if (llvm::Error Err =513 LookupInterface(ValuePrintingInfo[WithAlloc], VPName[WithAlloc]))514 return std::move(Err);515 516 if (Ctx.getLangOpts().CPlusPlus) {517 if (llvm::Error Err =518 LookupInterface(ValuePrintingInfo[NewTag], VPName[NewTag]))519 return std::move(Err);520 }521 }522 523 llvm::SmallVector<Expr *, 4> AdjustedArgs;524 // Create parameter `ThisInterp`.525 AdjustedArgs.push_back(CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this));526 527 // Create parameter `OutVal`.528 AdjustedArgs.push_back(529 CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue));530 531 // Build `__clang_Interpreter_SetValue*` call.532 533 // Get rid of ExprWithCleanups.534 if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))535 E = EWC->getSubExpr();536 537 QualType Ty = E->IgnoreImpCasts()->getType();538 QualType DesugaredTy = Ty.getDesugaredType(Ctx);539 540 // For lvalue struct, we treat it as a reference.541 if (DesugaredTy->isRecordType() && E->IgnoreImpCasts()->isLValue()) {542 DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);543 Ty = Ctx.getLValueReferenceType(Ty);544 }545 546 Expr *TypeArg =547 CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());548 // The QualType parameter `OpaqueType`, represented as `void*`.549 AdjustedArgs.push_back(TypeArg);550 551 // We push the last parameter based on the type of the Expr. Note we need552 // special care for rvalue struct.553 InterfaceKindVisitor V(S, E, AdjustedArgs);554 Scope *Scope = nullptr;555 ExprResult SetValueE;556 InterfaceKind Kind = V.computeInterfaceKind(DesugaredTy);557 switch (Kind) {558 case InterfaceKind::WithAlloc:559 [[fallthrough]];560 case InterfaceKind::CopyArray: {561 // __clang_Interpreter_SetValueWithAlloc.562 ExprResult AllocCall =563 S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::WithAlloc],564 E->getBeginLoc(), AdjustedArgs, E->getEndLoc());565 if (AllocCall.isInvalid())566 return llvm::make_error<llvm::StringError>(567 "Cannot call to " + VPName[WithAlloc],568 llvm::inconvertibleErrorCode());569 570 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());571 572 // Force CodeGen to emit destructor.573 if (auto *RD = Ty->getAsCXXRecordDecl()) {574 auto *Dtor = S.LookupDestructor(RD);575 Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));576 getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(577 DeclGroupRef(Dtor));578 }579 580 // __clang_Interpreter_SetValueCopyArr.581 if (Kind == InterfaceKind::CopyArray) {582 const auto *CATy = cast<ConstantArrayType>(DesugaredTy.getTypePtr());583 size_t ArrSize = Ctx.getConstantArrayElementCount(CATy);584 585 if (!Ctx.getLangOpts().CPlusPlus)586 ArrSize *= Ctx.getTypeSizeInChars(CATy->getBaseElementTypeUnsafe())587 .getQuantity();588 589 Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);590 Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};591 SetValueE =592 S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::CopyArray],593 SourceLocation(), Args, SourceLocation());594 if (SetValueE.isInvalid())595 return llvm::make_error<llvm::StringError>(596 "Cannot call to " + VPName[CopyArray],597 llvm::inconvertibleErrorCode());598 break;599 }600 Expr *Args[] = {AllocCall.get(), ValuePrintingInfo[InterfaceKind::NewTag]};601 ExprResult CXXNewCall = S.BuildCXXNew(602 E->getSourceRange(),603 /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,604 /*PlacementRParen=*/SourceLocation(),605 /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,606 E->getSourceRange(), E);607 608 if (CXXNewCall.isInvalid())609 return llvm::make_error<llvm::StringError>(610 "Cannot build a call to placement new",611 llvm::inconvertibleErrorCode());612 613 SetValueE = S.ActOnFinishFullExpr(CXXNewCall.get(),614 /*DiscardedValue=*/false);615 break;616 }617 // __clang_Interpreter_SetValueNoAlloc.618 case InterfaceKind::NoAlloc: {619 SetValueE =620 S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::NoAlloc],621 E->getBeginLoc(), AdjustedArgs, E->getEndLoc());622 break;623 }624 default:625 llvm_unreachable("Unhandled InterfaceKind");626 }627 628 // It could fail, like printing an array type in C. (not supported)629 if (SetValueE.isInvalid())630 return E;631 632 return SetValueE.get();633}634 635} // namespace clang636 637using namespace clang;638 639// Temporary rvalue struct that need special care.640extern "C" {641REPL_EXTERNAL_VISIBILITY void *642__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,643 void *OpaqueType) {644 Value &VRef = *(Value *)OutVal;645 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);646 return VRef.getPtr();647}648 649REPL_EXTERNAL_VISIBILITY void650__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,651 ...) {652 Value &VRef = *(Value *)OutVal;653 Interpreter *I = static_cast<Interpreter *>(This);654 VRef = Value(I, OpaqueType);655 if (VRef.isVoid())656 return;657 658 va_list args;659 va_start(args, /*last named param*/ OpaqueType);660 661 QualType QT = VRef.getType();662 if (VRef.getKind() == Value::K_PtrOrObj) {663 VRef.setPtr(va_arg(args, void *));664 } else {665 if (const auto *ED = QT->getAsEnumDecl())666 QT = ED->getIntegerType();667 switch (QT->castAs<BuiltinType>()->getKind()) {668 default:669 llvm_unreachable("unknown type kind!");670 break;671 // Types shorter than int are resolved as int, else va_arg has UB.672 case BuiltinType::Bool:673 VRef.setBool(va_arg(args, int));674 break;675 case BuiltinType::Char_S:676 VRef.setChar_S(va_arg(args, int));677 break;678 case BuiltinType::SChar:679 VRef.setSChar(va_arg(args, int));680 break;681 case BuiltinType::Char_U:682 VRef.setChar_U(va_arg(args, unsigned));683 break;684 case BuiltinType::UChar:685 VRef.setUChar(va_arg(args, unsigned));686 break;687 case BuiltinType::Short:688 VRef.setShort(va_arg(args, int));689 break;690 case BuiltinType::UShort:691 VRef.setUShort(va_arg(args, unsigned));692 break;693 case BuiltinType::Int:694 VRef.setInt(va_arg(args, int));695 break;696 case BuiltinType::UInt:697 VRef.setUInt(va_arg(args, unsigned));698 break;699 case BuiltinType::Long:700 VRef.setLong(va_arg(args, long));701 break;702 case BuiltinType::ULong:703 VRef.setULong(va_arg(args, unsigned long));704 break;705 case BuiltinType::LongLong:706 VRef.setLongLong(va_arg(args, long long));707 break;708 case BuiltinType::ULongLong:709 VRef.setULongLong(va_arg(args, unsigned long long));710 break;711 // Types shorter than double are resolved as double, else va_arg has UB.712 case BuiltinType::Float:713 VRef.setFloat(va_arg(args, double));714 break;715 case BuiltinType::Double:716 VRef.setDouble(va_arg(args, double));717 break;718 case BuiltinType::LongDouble:719 VRef.setLongDouble(va_arg(args, long double));720 break;721 // See REPL_BUILTIN_TYPES.722 }723 }724 va_end(args);725}726}727 728// A trampoline to work around the fact that operator placement new cannot729// really be forward declared due to libc++ and libstdc++ declaration mismatch.730// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same731// definition in the interpreter runtime. We should move it in a runtime header732// which gets included by the interpreter and here.733struct __clang_Interpreter_NewTag {};734REPL_EXTERNAL_VISIBILITY void *735operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {736 // Just forward to the standard operator placement new.737 return operator new(__sz, __p);738}739