brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.9 KiB · cfa50ee Raw
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