xref: /freebsd/contrib/llvm-project/clang/lib/Interpreter/InterpreterValuePrinter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements routines for in-process value printing in clang-repl.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "IncrementalParser.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/Sema/Lookup.h"
22 #include "clang/Sema/Sema.h"
23 
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/raw_ostream.h"
26 
27 #include <cassert>
28 
29 #include <cstdarg>
30 
31 namespace clang {
32 
33 llvm::Expected<llvm::orc::ExecutorAddr>
CompileDtorCall(CXXRecordDecl * CXXRD)34 Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
35   assert(CXXRD && "Cannot compile a destructor for a nullptr");
36   if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end())
37     return Dtor->getSecond();
38 
39   if (CXXRD->hasIrrelevantDestructor())
40     return llvm::orc::ExecutorAddr{};
41 
42   CXXDestructorDecl *DtorRD =
43       getCompilerInstance()->getSema().LookupDestructor(CXXRD);
44 
45   llvm::StringRef Name =
46       getCodeGen()->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
47   auto AddrOrErr = getSymbolAddress(Name);
48   if (!AddrOrErr)
49     return AddrOrErr.takeError();
50 
51   Dtors[CXXRD] = *AddrOrErr;
52   return AddrOrErr;
53 }
54 
55 enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };
56 
57 class InterfaceKindVisitor
58     : public TypeVisitor<InterfaceKindVisitor, InterfaceKind> {
59 
60   Sema &S;
61   Expr *E;
62   llvm::SmallVectorImpl<Expr *> &Args;
63 
64 public:
InterfaceKindVisitor(Sema & S,Expr * E,llvm::SmallVectorImpl<Expr * > & Args)65   InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args)
66       : S(S), E(E), Args(Args) {}
67 
computeInterfaceKind(QualType Ty)68   InterfaceKind computeInterfaceKind(QualType Ty) {
69     return Visit(Ty.getTypePtr());
70   }
71 
VisitRecordType(const RecordType * Ty)72   InterfaceKind VisitRecordType(const RecordType *Ty) {
73     return InterfaceKind::WithAlloc;
74   }
75 
VisitMemberPointerType(const MemberPointerType * Ty)76   InterfaceKind VisitMemberPointerType(const MemberPointerType *Ty) {
77     return InterfaceKind::WithAlloc;
78   }
79 
VisitConstantArrayType(const ConstantArrayType * Ty)80   InterfaceKind VisitConstantArrayType(const ConstantArrayType *Ty) {
81     return InterfaceKind::CopyArray;
82   }
83 
VisitFunctionProtoType(const FunctionProtoType * Ty)84   InterfaceKind VisitFunctionProtoType(const FunctionProtoType *Ty) {
85     HandlePtrType(Ty);
86     return InterfaceKind::NoAlloc;
87   }
88 
VisitPointerType(const PointerType * Ty)89   InterfaceKind VisitPointerType(const PointerType *Ty) {
90     HandlePtrType(Ty);
91     return InterfaceKind::NoAlloc;
92   }
93 
VisitReferenceType(const ReferenceType * Ty)94   InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
95     ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
96     assert(!AddrOfE.isInvalid() && "Can not create unary expression");
97     Args.push_back(AddrOfE.get());
98     return InterfaceKind::NoAlloc;
99   }
100 
VisitBuiltinType(const BuiltinType * Ty)101   InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
102     if (Ty->isNullPtrType())
103       Args.push_back(E);
104     else if (Ty->isFloatingType())
105       Args.push_back(E);
106     else if (Ty->isIntegralOrEnumerationType())
107       HandleIntegralOrEnumType(Ty);
108     else if (Ty->isVoidType()) {
109       // Do we need to still run `E`?
110     }
111 
112     return InterfaceKind::NoAlloc;
113   }
114 
VisitEnumType(const EnumType * Ty)115   InterfaceKind VisitEnumType(const EnumType *Ty) {
116     HandleIntegralOrEnumType(Ty);
117     return InterfaceKind::NoAlloc;
118   }
119 
120 private:
121   // Force cast these types to the uint that fits the register size. That way we
122   // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.
HandleIntegralOrEnumType(const Type * Ty)123   void HandleIntegralOrEnumType(const Type *Ty) {
124     ASTContext &Ctx = S.getASTContext();
125     uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);
126     QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits);
127     TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy);
128     ExprResult CastedExpr =
129         S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
130     assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
131     Args.push_back(CastedExpr.get());
132   }
133 
HandlePtrType(const Type * Ty)134   void HandlePtrType(const Type *Ty) {
135     ASTContext &Ctx = S.getASTContext();
136     TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);
137     ExprResult CastedExpr =
138         S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
139     assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
140     Args.push_back(CastedExpr.get());
141   }
142 };
143 
144 // This synthesizes a call expression to a speciall
145 // function that is responsible for generating the Value.
146 // In general, we transform:
147 //   clang-repl> x
148 // To:
149 //   // 1. If x is a built-in type like int, float.
150 //   __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);
151 //   // 2. If x is a struct, and a lvalue.
152 //   __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,
153 //   &x);
154 //   // 3. If x is a struct, but a rvalue.
155 //   new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
156 //   xQualType)) (x);
ExtractValueFromExpr(Expr * E)157 llvm::Expected<Expr *> Interpreter::ExtractValueFromExpr(Expr *E) {
158   Sema &S = getCompilerInstance()->getSema();
159   ASTContext &Ctx = S.getASTContext();
160 
161   // Find the value printing builtins.
162   if (!ValuePrintingInfo[0]) {
163     assert(llvm::all_of(ValuePrintingInfo, [](Expr *E) { return !E; }));
164 
165     auto LookupInterface = [&](Expr *&Interface,
166                                llvm::StringRef Name) -> llvm::Error {
167       LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
168                      Sema::LookupOrdinaryName,
169                      RedeclarationKind::ForVisibleRedeclaration);
170       S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
171       if (R.empty())
172         return llvm::make_error<llvm::StringError>(
173             Name + " not found!", llvm::inconvertibleErrorCode());
174 
175       CXXScopeSpec CSS;
176       Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();
177       return llvm::Error::success();
178     };
179     static constexpr llvm::StringRef Builtin[] = {
180         "__clang_Interpreter_SetValueNoAlloc",
181         "__clang_Interpreter_SetValueWithAlloc",
182         "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
183     if (llvm::Error Err =
184             LookupInterface(ValuePrintingInfo[NoAlloc], Builtin[NoAlloc]))
185       return std::move(Err);
186 
187     if (Ctx.getLangOpts().CPlusPlus) {
188       if (llvm::Error Err =
189               LookupInterface(ValuePrintingInfo[WithAlloc], Builtin[WithAlloc]))
190         return std::move(Err);
191       if (llvm::Error Err =
192               LookupInterface(ValuePrintingInfo[CopyArray], Builtin[CopyArray]))
193         return std::move(Err);
194       if (llvm::Error Err =
195               LookupInterface(ValuePrintingInfo[NewTag], Builtin[NewTag]))
196         return std::move(Err);
197     }
198   }
199 
200   llvm::SmallVector<Expr *, 4> AdjustedArgs;
201   // Create parameter `ThisInterp`.
202   AdjustedArgs.push_back(CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this));
203 
204   // Create parameter `OutVal`.
205   AdjustedArgs.push_back(
206       CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue));
207 
208   // Build `__clang_Interpreter_SetValue*` call.
209 
210   // Get rid of ExprWithCleanups.
211   if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
212     E = EWC->getSubExpr();
213 
214   QualType Ty = E->getType();
215   QualType DesugaredTy = Ty.getDesugaredType(Ctx);
216 
217   // For lvalue struct, we treat it as a reference.
218   if (DesugaredTy->isRecordType() && E->isLValue()) {
219     DesugaredTy = Ctx.getLValueReferenceType(DesugaredTy);
220     Ty = Ctx.getLValueReferenceType(Ty);
221   }
222 
223   Expr *TypeArg =
224       CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
225   // The QualType parameter `OpaqueType`, represented as `void*`.
226   AdjustedArgs.push_back(TypeArg);
227 
228   // We push the last parameter based on the type of the Expr. Note we need
229   // special care for rvalue struct.
230   InterfaceKindVisitor V(S, E, AdjustedArgs);
231   Scope *Scope = nullptr;
232   ExprResult SetValueE;
233   InterfaceKind Kind = V.computeInterfaceKind(DesugaredTy);
234   switch (Kind) {
235   case InterfaceKind::WithAlloc:
236     LLVM_FALLTHROUGH;
237   case InterfaceKind::CopyArray: {
238     // __clang_Interpreter_SetValueWithAlloc.
239     ExprResult AllocCall =
240         S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::WithAlloc],
241                         E->getBeginLoc(), AdjustedArgs, E->getEndLoc());
242     assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
243 
244     TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
245 
246     // Force CodeGen to emit destructor.
247     if (auto *RD = Ty->getAsCXXRecordDecl()) {
248       auto *Dtor = S.LookupDestructor(RD);
249       Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
250       getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
251           DeclGroupRef(Dtor));
252     }
253 
254     // __clang_Interpreter_SetValueCopyArr.
255     if (Kind == InterfaceKind::CopyArray) {
256       const auto *ConstantArrTy =
257           cast<ConstantArrayType>(DesugaredTy.getTypePtr());
258       size_t ArrSize = Ctx.getConstantArrayElementCount(ConstantArrTy);
259       Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);
260       Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
261       SetValueE =
262           S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::CopyArray],
263                           SourceLocation(), Args, SourceLocation());
264     }
265     Expr *Args[] = {AllocCall.get(), ValuePrintingInfo[InterfaceKind::NewTag]};
266     ExprResult CXXNewCall = S.BuildCXXNew(
267         E->getSourceRange(),
268         /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
269         /*PlacementRParen=*/SourceLocation(),
270         /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
271         E->getSourceRange(), E);
272 
273     assert(!CXXNewCall.isInvalid() &&
274            "Can't create runtime placement new call!");
275 
276     SetValueE = S.ActOnFinishFullExpr(CXXNewCall.get(),
277                                       /*DiscardedValue=*/false);
278     break;
279   }
280   // __clang_Interpreter_SetValueNoAlloc.
281   case InterfaceKind::NoAlloc: {
282     SetValueE =
283         S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::NoAlloc],
284                         E->getBeginLoc(), AdjustedArgs, E->getEndLoc());
285     break;
286   }
287   default:
288     llvm_unreachable("Unhandled InterfaceKind");
289   }
290 
291   // It could fail, like printing an array type in C. (not supported)
292   if (SetValueE.isInvalid())
293     return E;
294 
295   return SetValueE.get();
296 }
297 
298 } // namespace clang
299 
300 using namespace clang;
301 
302 // Temporary rvalue struct that need special care.
303 REPL_EXTERNAL_VISIBILITY void *
__clang_Interpreter_SetValueWithAlloc(void * This,void * OutVal,void * OpaqueType)304 __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
305                                       void *OpaqueType) {
306   Value &VRef = *(Value *)OutVal;
307   VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
308   return VRef.getPtr();
309 }
310 
__clang_Interpreter_SetValueNoAlloc(void * This,void * OutVal,void * OpaqueType,...)311 extern "C" void REPL_EXTERNAL_VISIBILITY __clang_Interpreter_SetValueNoAlloc(
312     void *This, void *OutVal, void *OpaqueType, ...) {
313   Value &VRef = *(Value *)OutVal;
314   Interpreter *I = static_cast<Interpreter *>(This);
315   VRef = Value(I, OpaqueType);
316   if (VRef.isVoid())
317     return;
318 
319   va_list args;
320   va_start(args, /*last named param*/ OpaqueType);
321 
322   QualType QT = VRef.getType();
323   if (VRef.getKind() == Value::K_PtrOrObj) {
324     VRef.setPtr(va_arg(args, void *));
325   } else {
326     if (const auto *ET = QT->getAs<EnumType>())
327       QT = ET->getDecl()->getIntegerType();
328     switch (QT->castAs<BuiltinType>()->getKind()) {
329     default:
330       llvm_unreachable("unknown type kind!");
331       break;
332       // Types shorter than int are resolved as int, else va_arg has UB.
333     case BuiltinType::Bool:
334       VRef.setBool(va_arg(args, int));
335       break;
336     case BuiltinType::Char_S:
337       VRef.setChar_S(va_arg(args, int));
338       break;
339     case BuiltinType::SChar:
340       VRef.setSChar(va_arg(args, int));
341       break;
342     case BuiltinType::Char_U:
343       VRef.setChar_U(va_arg(args, unsigned));
344       break;
345     case BuiltinType::UChar:
346       VRef.setUChar(va_arg(args, unsigned));
347       break;
348     case BuiltinType::Short:
349       VRef.setShort(va_arg(args, int));
350       break;
351     case BuiltinType::UShort:
352       VRef.setUShort(va_arg(args, unsigned));
353       break;
354     case BuiltinType::Int:
355       VRef.setInt(va_arg(args, int));
356       break;
357     case BuiltinType::UInt:
358       VRef.setUInt(va_arg(args, unsigned));
359       break;
360     case BuiltinType::Long:
361       VRef.setLong(va_arg(args, long));
362       break;
363     case BuiltinType::ULong:
364       VRef.setULong(va_arg(args, unsigned long));
365       break;
366     case BuiltinType::LongLong:
367       VRef.setLongLong(va_arg(args, long long));
368       break;
369     case BuiltinType::ULongLong:
370       VRef.setULongLong(va_arg(args, unsigned long long));
371       break;
372       // Types shorter than double are resolved as double, else va_arg has UB.
373     case BuiltinType::Float:
374       VRef.setFloat(va_arg(args, double));
375       break;
376     case BuiltinType::Double:
377       VRef.setDouble(va_arg(args, double));
378       break;
379     case BuiltinType::LongDouble:
380       VRef.setLongDouble(va_arg(args, long double));
381       break;
382       // See REPL_BUILTIN_TYPES.
383     }
384   }
385   va_end(args);
386 }
387 
388 // A trampoline to work around the fact that operator placement new cannot
389 // really be forward declared due to libc++ and libstdc++ declaration mismatch.
390 // FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
391 // definition in the interpreter runtime. We should move it in a runtime header
392 // which gets included by the interpreter and here.
393 struct __clang_Interpreter_NewTag {};
394 REPL_EXTERNAL_VISIBILITY void *
operator new(size_t __sz,void * __p,__clang_Interpreter_NewTag)395 operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
396   // Just forward to the standard operator placement new.
397   return operator new(__sz, __p);
398 }
399