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