CppInterOp
C++ Language Interoperability Layer
Loading...
Searching...
No Matches
CppInterOp.cpp
Go to the documentation of this file.
1//--------------------------------------------------------------------*- C++ -*-
2// CLING - the C++ LLVM-based InterpreterG :)
3// author: Vassil Vassilev <vvasilev@cern.ch>
4//
5// This file is dual-licensed: you can choose to license it under the University
6// of Illinois Open Source License or the GNU Lesser General Public License. See
7// LICENSE.TXT for details.
8//------------------------------------------------------------------------------
9
11#include "Unwrap.h"
12#include "CppInterOp/Error.h"
13
14#include "Compatibility.h"
15#include "ErrorInternal.h"
16#include "InterpreterInfo.h"
17#include "Sins.h" // for access to private members
18#include "Tracing.h"
19
20// MSan workaround for clang-repl <= 22: __clang_Interpreter_SetValueNoAlloc
21// receives JIT-emitted values through varargs, and MSan cannot track shadow
22// across that JIT/native boundary -- the returned Value carries correct bits
23// but an uninit shadow, which trips downstream reads (convertTo, ~Value).
24// Fixed upstream in llvm/llvm-project#196894; unpoison locally for older LLVM.
25#if defined(__has_feature)
26#if __has_feature(memory_sanitizer) && LLVM_VERSION_MAJOR <= 22
27#include <sanitizer/msan_interface.h>
28#define CPPINTEROP_MSAN_UNPOISON_VALUE(v) __msan_unpoison(&(v), sizeof(v))
29#else
30#define CPPINTEROP_MSAN_UNPOISON_VALUE(v) ((void)0)
31#endif
32#else
33#define CPPINTEROP_MSAN_UNPOISON_VALUE(v) ((void)0)
34#endif
35
36#include "clang/AST/Attrs.inc"
37#include "clang/AST/CXXInheritance.h"
38#include "clang/AST/Comment.h"
39#include "clang/AST/Decl.h"
40#include "clang/AST/DeclAccessPair.h"
41#include "clang/AST/DeclBase.h"
42#include "clang/AST/DeclCXX.h"
43#include "clang/AST/DeclTemplate.h"
44#include "clang/AST/DeclarationName.h"
45#include "clang/AST/Expr.h"
46#include "clang/AST/ExprCXX.h"
47#include "clang/AST/GlobalDecl.h"
48#include "clang/AST/Mangle.h"
49#include "clang/AST/NestedNameSpecifier.h"
50#include "clang/AST/OperationKinds.h"
51#include "clang/AST/QualTypeNames.h"
52#include "clang/AST/RawCommentList.h"
53#include "clang/AST/RecordLayout.h"
54#include "clang/AST/RecursiveASTVisitor.h"
55#include "clang/AST/Stmt.h"
56#include "clang/AST/Type.h"
57#include "clang/AST/VTableBuilder.h"
58#include "clang/Basic/Builtins.h"
59#include "clang/Basic/CharInfo.h"
60#include "clang/Basic/Diagnostic.h"
61#include "clang/Basic/DiagnosticSema.h"
62#include "clang/Basic/LangStandard.h"
63#include "clang/Basic/Linkage.h"
64#include "clang/Basic/OperatorKinds.h"
65#include "clang/Basic/SourceLocation.h"
66#include "clang/Basic/SourceManager.h"
67#include "clang/Basic/Specifiers.h"
68#include "clang/Basic/Version.h"
69#include "clang/Frontend/CompilerInstance.h"
70#include "clang/Interpreter/Interpreter.h"
71#include "clang/Sema/Lookup.h"
72#include "clang/Sema/Overload.h"
73#include "clang/Sema/Ownership.h"
74#include "clang/Sema/Redeclaration.h"
75#include "clang/Sema/Sema.h"
76#include "clang/Sema/TemplateDeduction.h"
77
78#include "llvm/ADT/STLExtras.h"
79#include "llvm/ADT/SmallString.h"
80#include "llvm/ADT/SmallVector.h"
81#include "llvm/ADT/StringRef.h"
82#include "llvm/Demangle/Demangle.h"
83#include "llvm/ExecutionEngine/JITSymbol.h"
84#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
85#include "llvm/ExecutionEngine/Orc/Core.h"
86#include "llvm/ExecutionEngine/Orc/CoreContainers.h"
87#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
88#include "llvm/IR/GlobalValue.h"
89#include "llvm/Support/Casting.h"
90#include "llvm/Support/CommandLine.h"
91#include "llvm/Support/Debug.h"
92#include "llvm/Support/Error.h"
93#include "llvm/Support/FileSystem.h"
94#include "llvm/Support/ManagedStatic.h"
95#include "llvm/Support/Path.h"
96#include "llvm/Support/Process.h"
97#include "llvm/Support/Signals.h"
98#include "llvm/Support/TargetSelect.h"
99#include "llvm/Support/raw_ostream.h"
100#include "llvm/TargetParser/Host.h"
101#include "llvm/TargetParser/Triple.h"
102
103#include <algorithm>
104#include <array>
105#include <cassert>
106#include <cstddef>
107#include <cstdint>
108#include <cstdio>
109#include <cstdlib>
110#include <cstring>
111#include <deque>
112#include <iostream>
113#include <iterator>
114#include <map>
115#include <memory>
116#include <mutex>
117#include <optional>
118#include <set>
119#include <sstream>
120#include <stack>
121#include <string>
122#include <sys/types.h>
123#ifndef _WIN32
124#include <unistd.h>
125#endif
126#include <unordered_map>
127#include <utility>
128// Stream redirect.
129#ifdef _WIN32
130#include <io.h>
131#ifndef STDOUT_FILENO
132#define STDOUT_FILENO 1
133#define STDERR_FILENO 2
134// For exec().
135#include <stdio.h>
136#define popen(x, y) (_popen(x, y))
137#define pclose (_pclose)
138#endif
139#else
140#include <dlfcn.h>
141#include <unistd.h>
142#endif // WIN32
143#include <vector>
144
145// Runtime symbols required if the library using JIT (Cpp::Evaluate) does
146// not link to llvm
147#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
150#if CLANG_VERSION_MAJOR > 21
151extern "C" void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
152 void* OpaqueType);
153#else
154void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
155 void* OpaqueType);
156#endif
157
158extern "C" void __clang_Interpreter_SetValueNoAlloc(void* This, void* OutVal,
159 void* OpaqueType, ...);
160#endif // CPPINTEROP_USE_CLING
161
162// LSan ships as part of ASan only on Linux and macOS. MSVC and
163// Emscripten set the ASan feature macros but do not provide
164// __lsan_ignore_object, so emitting the hook there would fail to
165// JIT-link the wrapper.
166#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && \
167 (defined(__SANITIZE_ADDRESS__) || \
168 (defined(__has_feature) && __has_feature(address_sanitizer)))
169#define CPPINTEROP_ASAN_BUILD 1
170#endif
171
172namespace Cpp {
173
174using namespace clang;
175using namespace llvm;
176
177static void DefaultProcessCrashHandler(void*);
178
179/// Set by UseExternalInterpreter to suppress llvm_shutdown at process exit
180/// -- the client owns LLVM in that case.
181static bool SkipShutDown = false;
182
183/// RAII guard whose dtor calls llvm_shutdown for the owned-interpreter case.
184/// Constructed as a function-local static AFTER sInterpreters, so its dtor
185/// fires FIRST (reverse-of-construction); llvm_shutdown then drains the
186/// ManagedStatic registry, including sInterpreters, deterministically.
187/// The llvm_shutdown call itself is gated on LLVM 23+, where
188/// Platform::lookupResolvedInitSymbols (llvm/llvm-project#196874) makes
189/// ~Interpreter's JIT deinit skip lazy materialization. On older LLVM
190/// the same chain SEGFAULTs in cleanUp against destroyed function-local
191/// statics, so the dtor is a no-op and sInterpreters leaks instead.
194 if (!SkipShutDown) {
195#if LLVM_VERSION_MAJOR > 22
196 llvm::llvm_shutdown();
197#endif
198 }
199 }
200};
201
202// Function-static storage for interpreters
203static std::deque<InterpreterInfo>&
204GetInterpreters(bool SetCrashHandler = true) {
205 static llvm::ManagedStatic<std::deque<InterpreterInfo>> sInterpreters;
206 static std::once_flag ProcessInitialized;
207 std::call_once(ProcessInitialized, [SetCrashHandler]() {
208 if (SetCrashHandler)
209 llvm::sys::PrintStackTraceOnErrorSignal("CppInterOp");
210
211 if (getenv("CPPINTEROP_LOG") != nullptr)
213
214 // Initialize all targets (required for device offloading)
215 llvm::InitializeAllTargetInfos();
216 llvm::InitializeAllTargets();
217 llvm::InitializeAllTargetMCs();
218 llvm::InitializeAllAsmParsers();
219 llvm::InitializeAllAsmPrinters();
220
221 // Pipe / OOM / crash handlers replicate what InitLLVM did before it was
222 // dropped. Skipped when the host owns LLVM -- they're its decision.
223 if (SetCrashHandler) {
224 llvm::sys::SetOneShotPipeSignalFunction(
225 llvm::sys::DefaultOneShotPipeSignalHandler);
226 llvm::sys::AddSignalHandler(DefaultProcessCrashHandler,
227 /*Cookie=*/nullptr);
228 llvm::install_out_of_memory_new_handler();
229 }
230 });
231
232 // Constructed after sInterpreters above, so its dtor fires first at
233 // process exit; see InterpreterShutdown.
234 static InterpreterShutdown Shutdown;
235
236 return *sInterpreters;
237}
238
239// Global crash handler for the entire process
240static void DefaultProcessCrashHandler(void*) {
241 // Access the static deque via the getter
242 std::deque<InterpreterInfo>& Interps = GetInterpreters();
243
244 llvm::errs() << "\n**************************************************\n";
245 llvm::errs() << " CppInterOp CRASH DETECTED\n";
248 if (!Path.empty())
249 llvm::errs() << " Reproducer saved to: " << Path << "\n";
250 else
251 llvm::errs() << " Failed to write reproducer file.\n";
252 } else {
253 llvm::errs() << " Re-run with CPPINTEROP_LOG=1 for a crash reproducer\n";
254 }
255
256 if (!Interps.empty()) {
257 llvm::errs() << " Active Interpreters:\n";
258 for (const auto& Info : Interps) {
259 if (Info.Interpreter)
260 llvm::errs() << " - " << Info.Interpreter << "\n";
261 }
262 }
263
264 llvm::errs() << "**************************************************\n";
265 llvm::errs().flush();
266
267 // Print backtrace (includes JIT symbols if registered)
268 llvm::sys::PrintStackTrace(llvm::errs());
269
270 llvm::errs() << "**************************************************\n";
271 llvm::errs().flush();
272
273 // The process must actually terminate for EXPECT_DEATH to pass.
274 // We use _exit to avoid calling atexit() handlers which might be corrupted.
275 llvm::sys::Process::Exit(/*RetCode=*/1, /*NoCleanup=*/false);
276}
277
278static void RegisterInterpreter(compat::Interpreter* I, bool Owned,
279 std::vector<std::string> ArgvStorage = {}) {
280 std::deque<InterpreterInfo>& Interps = GetInterpreters(Owned);
281 Interps.emplace_back(I, Owned, std::move(ArgvStorage));
282 InstallDiagConsumer(&Interps.back());
283}
284
286 auto& Interps = GetInterpreters();
287 assert(!Interps.empty() &&
288 "Interpreter instance must be set before calling this!");
289 if (I) {
290 for (auto& Info : Interps)
291 if (Info.Interpreter == I)
292 return Info;
293 }
294 return Interps.back();
295}
296
297static compat::Interpreter& getInterp(InterpRef I = nullptr) {
298 if (I)
299 return *unwrap<compat::Interpreter>(I);
300 return *getInterpInfo().Interpreter;
301}
302
304 return &getInterpInfo(I ? unwrap<compat::Interpreter>(I) : nullptr);
305}
306
307InterpRef GetInterpreter() {
309 std::deque<InterpreterInfo>& Interps = GetInterpreters();
310 if (Interps.empty())
311 return INTEROP_RETURN(nullptr);
312 return INTEROP_RETURN(Interps.back().Interpreter);
313}
314
315void UseExternalInterpreter(InterpRef I) {
316 INTEROP_TRACE(I);
317 assert(GetInterpreters(false).empty() && "sInterpreter already in use!");
318 SkipShutDown = true;
319 RegisterInterpreter(unwrap<compat::Interpreter>(I), /*Owned=*/false);
320 return INTEROP_VOID_RETURN();
321}
322
323bool ActivateInterpreter(InterpRef I) {
324 INTEROP_TRACE(I);
325 if (!I)
326 return INTEROP_RETURN(false);
327
328 std::deque<InterpreterInfo>& Interps = GetInterpreters();
329 auto* Interp = unwrap<compat::Interpreter>(I);
330 auto found =
331 std::find_if(Interps.begin(), Interps.end(), [Interp](const auto& Info) {
332 return Info.Interpreter == Interp;
333 });
334 if (found == Interps.end())
335 return INTEROP_RETURN(false);
336
337 if (std::next(found) != Interps.end()) // if not already last element.
338 std::rotate(found, found + 1, Interps.end());
339
340 return INTEROP_RETURN(true); // success
341}
342
343bool DeleteInterpreter(InterpRef I /*=nullptr*/) {
344 INTEROP_TRACE(I);
345 std::deque<InterpreterInfo>& Interps = GetInterpreters();
346 if (Interps.empty())
347 return INTEROP_RETURN(false);
348
349 if (!I) {
350 Interps.pop_back(); // Triggers ~InterpreterInfo() and potential delete
351 return INTEROP_RETURN(true);
352 }
353
354 auto* Interp = unwrap<compat::Interpreter>(I);
355 auto found =
356 std::find_if(Interps.begin(), Interps.end(), [Interp](const auto& Info) {
357 return Info.Interpreter == Interp;
358 });
359 if (found == Interps.end())
360 return INTEROP_RETURN(false); // failure
361
362 Interps.erase(found);
363 return INTEROP_RETURN(true);
364}
365
366static clang::Sema& getSema() { return getInterp().getCI()->getSema(); }
367static clang::ASTContext& getASTContext() { return getSema().getASTContext(); }
368
369static void ForceCodeGen(Decl* D, compat::Interpreter& I) {
370 // The decl was deferred by CodeGen. Force its emission.
371 // FIXME: In ASTContext::DeclMustBeEmitted we should check if the
372 // Decl::isUsed is set or we should be able to access CodeGen's
373 // addCompilerUsedGlobal.
374 ASTContext& C = I.getSema().getASTContext();
375
376 D->addAttr(UsedAttr::CreateImplicit(C));
377#ifdef CPPINTEROP_USE_CLING
378 cling::Interpreter::PushTransactionRAII RAII(&I);
379 I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(D));
380#else // CLANG_REPL
381 I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(D));
382 // Take the newest llvm::Module produced by CodeGen and send it to JIT.
383 auto GeneratedPTU = I.Parse("");
384 if (!GeneratedPTU)
385 llvm::logAllUnhandledErrors(GeneratedPTU.takeError(), llvm::errs(),
386 "[ForceCodeGen] Failed to generate PTU:");
387
388 // From cling's BackendPasses.cpp
389 // FIXME: We need to upstream this code in IncrementalExecutor::addModule
390 for (auto& GV : GeneratedPTU->TheModule->globals()) {
391 llvm::GlobalValue::LinkageTypes LT = GV.getLinkage();
392 if (GV.isDeclaration() || !GV.hasName() ||
393 GV.getName().starts_with(".str") ||
394 !llvm::GlobalVariable::isDiscardableIfUnused(LT) ||
395 LT != llvm::GlobalValue::InternalLinkage)
396 continue; // nothing to do
397 GV.setLinkage(llvm::GlobalValue::WeakAnyLinkage);
398 }
399 if (auto Err = I.Execute(*GeneratedPTU))
400 llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
401 "[ForceCodeGen] Failed to execute PTU:");
402#endif
403}
404
405#define DEBUG_TYPE "jitcall"
406bool JitCall::AreArgumentsValid(void* result, ArgList args, void* self,
407 size_t nary) const {
408 bool Valid = true;
409 if (Cpp::IsConstructor(m_FD)) {
410 assert(result && "Must pass the location of the created object!");
411 Valid &= (bool)result;
412 }
413 if (Cpp::GetFunctionRequiredArgs(m_FD) > args.m_ArgSize) {
414 assert(0 && "Must pass at least the minimal number of args!");
415 Valid = false;
416 }
417 if (args.m_ArgSize) {
418 assert(args.m_Args != nullptr && "Must pass an argument list!");
419 Valid &= (bool)args.m_Args;
420 }
421 if (!Cpp::IsConstructor(m_FD) && !Cpp::IsDestructor(m_FD) &&
422 Cpp::IsMethod(m_FD) && !Cpp::IsStaticMethod(m_FD)) {
423 assert(self && "Must pass the pointer to object");
424 Valid &= (bool)self;
425 }
426 const auto* FD = cast<FunctionDecl>(unwrap<Decl>(m_FD));
427 if (!FD->getReturnType()->isVoidType() && !result) {
428 assert(0 && "We are discarding the return TyRef of the function!");
429 Valid = false;
430 }
431 if (Cpp::IsConstructor(m_FD) && nary == 0UL) {
432 assert(0 && "Number of objects to construct should be atleast 1");
433 Valid = false;
434 }
435 if (Cpp::IsConstructor(m_FD)) {
436 const auto* CD = cast<CXXConstructorDecl>(unwrap<Decl>(m_FD));
437 if (CD->getMinRequiredArguments() != 0 && nary > 1) {
438 assert(0 &&
439 "Cannot pass initialization parameters to array new construction");
440 Valid = false;
441 }
442 }
443 assert(m_Kind != kDestructorCall && "Wrong overload!");
444 Valid &= m_Kind != kDestructorCall;
445 return Valid;
446}
447
448// Trace-hook impls reached via DispatchRaw from JitCall's inline body.
449// Off-trace the slot is nullptr and these never run.
450void CppInterOpTraceJitCallInvokeImpl(const JitCall* JC, void* result,
451 void** args, std::size_t nargs,
452 void* self) {
454 if (!TI)
455 return;
456 std::string Name;
457 llvm::raw_string_ostream OS(Name);
458 const auto* FD = unwrap<FunctionDecl>(JC->m_FD);
459 FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(),
460 /*Qualified=*/true);
461 LLVM_DEBUG(dbgs() << "Run '" << Name << "', compiled at: "
462 << (void*)JC->m_GenericCall << " with result at: " << result
463 << " , args at: " << args << " , arg count: " << nargs
464 << " , self at: " << self << "\n";);
465 std::string SelfPart = self ? TI->lookupHandle(self) : "";
466 TI->appendToLog(llvm::formatv(" // JitCall::Invoke {0}(nargs={1}, self={2})",
467 Name, nargs,
468 SelfPart.empty() ? "nullptr" : SelfPart));
469}
470
471void CppInterOpTraceJitCallInvokeDestructorImpl(const JitCall* JC, void* object,
472 unsigned long nary,
473 int withFree) {
475 if (!TI)
476 return;
477 std::string Name;
478 llvm::raw_string_ostream OS(Name);
479 const auto* FD = unwrap<FunctionDecl>(JC->m_FD);
480 FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(),
481 /*Qualified=*/true);
482 LLVM_DEBUG(dbgs() << "Finish '" << Name
483 << "', compiled at: " << (void*)JC->m_DestructorCall);
484 std::string ObjPart = object ? TI->lookupHandle(object) : "nullptr";
485 TI->appendToLog(
486 llvm::formatv(" // JitCall::InvokeDestructor {0}(object={1}, nary={2}, "
487 "withFree={3})",
488 Name, ObjPart, nary, withFree));
489}
490
491// Post-invoke trace hook reached via DispatchRaw. Constructors and
492// pointer/reference returns deposit a fresh T* at *result; registering
493// it as vN lets later trace lines render the name instead of
494// `nullptr /*unknown*/`. No-op for value or void returns.
495void CppInterOpTraceJitCallInvokeReturnImpl(const JitCall* JC, void* result) {
497 if (!TI || !result)
498 return;
499 const auto* FD = unwrap<FunctionDecl>(JC->m_FD);
500 bool RegisterPtr = isa<CXXConstructorDecl>(FD);
501 if (!RegisterPtr) {
502 QualType RT = FD->getReturnType();
503 RegisterPtr = RT->isPointerType() || RT->isReferenceType();
504 }
505 if (!RegisterPtr)
506 return;
507 if (void* p = *static_cast<void* const*>(result))
508 TI->getOrRegisterHandle(p);
509}
510
511#undef DEBUG_TYPE
512
513std::string GetVersion() {
515 const char* const VERSION = CPPINTEROP_VERSION;
516 std::string fullVersion = "CppInterOp version";
517 fullVersion += VERSION;
518 fullVersion += "\n (based on "
519#ifdef CPPINTEROP_USE_CLING
520 "cling ";
521#else
522 "clang-repl";
523#endif // CPPINTEROP_USE_CLING
524 return INTEROP_RETURN(fullVersion + "[" + clang::getClangFullVersion() +
525 "])\n");
526}
527
528std::string GetBuildInfo() {
530 // The right-hand side is a raw-string literal expression generated from
531 // BuildInfo.inc.in via configure_file at CMake-configure time; it carries
532 // the filtered CACHE_VARIABLES snapshot. Kept out of the INTEROP_RETURN
533 // macro call so the preprocessor is not asked to expand a directive
534 // inside macro arguments.
535 std::string Info =
536#include "CppInterOp/BuildInfo.inc"
537 ;
538 return INTEROP_RETURN(Info);
539}
540
541std::string Demangle(const std::string& mangled_name) {
542 INTEROP_TRACE(mangled_name);
543 // Both itaniumDemangle and microsoftDemangle return a malloc'd buffer
544 // that the caller owns; the implicit std::string conversion copies the
545 // bytes but never frees the original. See llvm/Demangle/Demangle.h.
546#ifdef _WIN32
547 char* Raw = microsoftDemangle(mangled_name, nullptr, nullptr);
548#else
549 char* Raw = llvm::itaniumDemangle(mangled_name);
550#endif
551 std::string demangle = Raw ? Raw : "";
552 std::free(Raw);
553 return INTEROP_RETURN(demangle);
554}
555
556void EnableDebugOutput(bool value /* =true*/) {
557 INTEROP_TRACE(value);
558 llvm::DebugFlag = value;
559 return INTEROP_VOID_RETURN();
560}
561
564 return INTEROP_RETURN(llvm::DebugFlag);
565}
566
567static void InstantiateFunctionDefinition(Decl* D) {
569 if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
570 getSema().InstantiateFunctionDefinition(SourceLocation(), FD,
571 /*Recursive=*/true,
572 /*DefinitionRequired=*/true);
573 // FIXME: this can go into a RAII object
574 clang::DiagnosticsEngine& Diags = getSema().getDiagnostics();
575 if (!FD->isDefined() && Diags.hasErrorOccurred()) {
576 // instantiation failed, need to reset DiagnosticsEngine
577 Diags.Reset(/*soft=*/true);
578 Diags.getClient()->clear();
579 }
580 }
581}
582
583bool IsAggregate(ConstDeclRef DRef) {
584 INTEROP_TRACE(DRef);
585 const auto* D = unwrap<Decl>(DRef);
586
587 // Aggregates are only arrays or tag decls.
588 if (const auto* ValD = dyn_cast<ValueDecl>(D))
589 if (ValD->getType()->isArrayType())
590 return INTEROP_RETURN(true);
591
592 // struct, class, union
593 if (const auto* CXXRD = dyn_cast<CXXRecordDecl>(D))
594 return INTEROP_RETURN(CXXRD->isAggregate());
595
596 return INTEROP_RETURN(false);
597}
598
599bool IsNamespace(ConstDeclRef DRef) {
600 INTEROP_TRACE(DRef);
601 const auto* D = unwrap<Decl>(DRef);
602 return INTEROP_RETURN(isa<NamespaceDecl>(D));
603}
604
605bool IsClass(ConstDeclRef DRef) {
606 INTEROP_TRACE(DRef);
607 const auto* D = unwrap<Decl>(DRef);
608 return INTEROP_RETURN(isa<CXXRecordDecl>(D));
609}
610
611bool IsFunction(ConstDeclRef DRef) {
612 INTEROP_TRACE(DRef);
613 const auto* D = unwrap<Decl>(DRef);
614 return INTEROP_RETURN(isa<FunctionDecl>(D));
615}
616
617bool IsFunctionPointerType(ConstTypeRef TyRef) {
618 INTEROP_TRACE(TyRef);
619 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
620 return INTEROP_RETURN(QT->isFunctionPointerType());
621}
622
623bool IsClassPolymorphic(ConstDeclRef DRef) {
624 INTEROP_TRACE(DRef);
625 const auto* D = unwrap<Decl>(DRef);
626 if (const auto* CXXRD = llvm::dyn_cast<CXXRecordDecl>(D))
627 if (const auto* CXXRDD = CXXRD->getDefinition())
628 return INTEROP_RETURN(CXXRDD->isPolymorphic());
629 return INTEROP_RETURN(false);
630}
631
632static SourceLocation GetValidSLoc(Sema& semaRef) {
633 auto& SM = semaRef.getSourceManager();
634 return SM.getLocForStartOfFile(SM.getMainFileID());
635}
636
637// See TClingClassInfo::IsLoaded
638bool IsComplete(ConstDeclRef DRef) {
639 INTEROP_TRACE(DRef);
640 if (!DRef)
641 return INTEROP_RETURN(false);
642
643 const auto* D = unwrap<Decl>(DRef);
644
645 if (isa<ClassTemplateSpecializationDecl>(D)) {
646 QualType QT = QualType::getFromOpaquePtr(GetTypeFromScope(DRef).data);
647 clang::Sema& S = getSema();
648 SourceLocation fakeLoc = GetValidSLoc(S);
650 return INTEROP_RETURN(S.isCompleteType(fakeLoc, QT));
651 }
652
653 if (const auto* CXXRD = dyn_cast<CXXRecordDecl>(D))
654 return INTEROP_RETURN(CXXRD->hasDefinition());
655 else if (const auto* TD = dyn_cast<TagDecl>(D))
656 return INTEROP_RETURN(TD->getDefinition());
657
658 // Everything else is considered complete.
659 return INTEROP_RETURN(true);
660}
661
662size_t SizeOf(ConstDeclRef DRef) {
663 INTEROP_TRACE(DRef);
664 assert(DRef);
665 if (!IsComplete(DRef))
666 return INTEROP_RETURN(0);
667
668 if (const auto* RD = dyn_cast<RecordDecl>(unwrap<Decl>(DRef))) {
669 ASTContext& Context = RD->getASTContext();
670 const ASTRecordLayout& Layout = Context.getASTRecordLayout(RD);
671 return INTEROP_RETURN(Layout.getSize().getQuantity());
672 }
673
674 return INTEROP_RETURN(0);
675}
676
677bool IsBuiltin(ConstTypeRef TyRef) {
678 INTEROP_TRACE(TyRef);
679 QualType Ty = QualType::getFromOpaquePtr(TyRef.data);
680 if (Ty->isBuiltinType() || Ty->isAnyComplexType())
681 return INTEROP_RETURN(true);
682 // Check for std::complex<T> specializations.
683 if (const auto* RD = Ty->getAsCXXRecordDecl()) {
684 if (const auto* CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
685 IdentifierInfo* II = CTSD->getSpecializedTemplate()->getIdentifier();
686 if (II && II->isStr("complex") &&
687 CTSD->getDeclContext()->isStdNamespace())
688 return INTEROP_RETURN(true);
689 }
690 }
691 return INTEROP_RETURN(false);
692}
693
694bool IsTemplate(ConstDeclRef DRef) {
695 INTEROP_TRACE(DRef);
696 const auto* D = unwrap<clang::Decl>(DRef);
697 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::TemplateDecl>(D));
698}
699
700bool IsTemplateSpecialization(ConstDeclRef DRef) {
701 INTEROP_TRACE(DRef);
702 const auto* D = unwrap<clang::Decl>(DRef);
703 return INTEROP_RETURN(
704 llvm::isa_and_nonnull<clang::ClassTemplateSpecializationDecl>(D));
705}
706
707bool IsTypedefed(ConstDeclRef DRef) {
708 INTEROP_TRACE(DRef);
709 const auto* D = unwrap<clang::Decl>(DRef);
710 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::TypedefNameDecl>(D));
711}
712
713bool IsAbstract(ConstDeclRef DRef) {
714 INTEROP_TRACE(DRef);
715 const auto* D = unwrap<clang::Decl>(DRef);
716 if (const auto* CXXRD = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(D))
717 return INTEROP_RETURN(CXXRD->isAbstract());
718
719 return INTEROP_RETURN(false);
720}
721
722bool IsEnumScope(ConstDeclRef DRef) {
723 INTEROP_TRACE(DRef);
724 const auto* D = unwrap<clang::Decl>(DRef);
725 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::EnumDecl>(D));
726}
727
728bool IsEnumConstant(ConstDeclRef DRef) {
729 INTEROP_TRACE(DRef);
730 const auto* D = unwrap<clang::Decl>(DRef);
731 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::EnumConstantDecl>(D));
732}
733
734bool IsEnumType(ConstTypeRef TyRef) {
735 INTEROP_TRACE(TyRef);
736 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
737 return INTEROP_RETURN(QT->isEnumeralType());
738}
739
740static bool isSmartPointer(const RecordType* RT) {
741 auto IsUseCountPresent = [](const RecordDecl* Record) {
742 ASTContext& C = Record->getASTContext();
743 return !Record->lookup(&C.Idents.get("use_count")).empty();
744 };
745 auto IsOverloadedOperatorPresent = [](const RecordDecl* Record,
746 OverloadedOperatorKind Op) {
747 ASTContext& C = Record->getASTContext();
748 DeclContextLookupResult Result =
749 Record->lookup(C.DeclarationNames.getCXXOperatorName(Op));
750 return !Result.empty();
751 };
752
753 const RecordDecl* Record = RT->getDecl();
754 if (IsUseCountPresent(Record))
755 return true;
756
757 bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
758 bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
759 if (foundStarOperator && foundArrowOperator)
760 return true;
761
762 const auto* CXXRecord = dyn_cast<CXXRecordDecl>(Record);
763 if (!CXXRecord)
764 return false;
765
766 auto FindOverloadedOperators = [&](const CXXRecordDecl* Base) {
767 // If we find use_count, we are done.
768 if (IsUseCountPresent(Base))
769 return false; // success.
770 if (!foundStarOperator)
771 foundStarOperator = IsOverloadedOperatorPresent(Base, OO_Star);
772 if (!foundArrowOperator)
773 foundArrowOperator = IsOverloadedOperatorPresent(Base, OO_Arrow);
774 if (foundStarOperator && foundArrowOperator)
775 return false; // success.
776 return true;
777 };
778
779 return !CXXRecord->forallBases(FindOverloadedOperators);
780}
781
782bool IsSmartPtrType(ConstTypeRef TyRef) {
783 INTEROP_TRACE(TyRef);
784 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
785 if (const RecordType* RT = QT->getAs<RecordType>()) {
786 // Add quick checks for the std smart prts to cover most of the cases.
787 std::string typeString = GetTypeAsString(TyRef);
788 llvm::StringRef tsRef(typeString);
789 if (tsRef.starts_with("std::unique_ptr") ||
790 tsRef.starts_with("std::shared_ptr") ||
791 tsRef.starts_with("std::weak_ptr"))
792 return INTEROP_RETURN(true);
793 return INTEROP_RETURN(isSmartPointer(RT));
794 }
795 return INTEROP_RETURN(false);
796}
797
798TypeRef GetIntegerTypeFromEnumScope(ConstDeclRef DRef) {
799 INTEROP_TRACE(DRef);
800 const auto* D = unwrap<clang::Decl>(DRef);
801 if (const auto* ED = llvm::dyn_cast_or_null<clang::EnumDecl>(D)) {
802 return INTEROP_RETURN(ED->getIntegerType().getAsOpaquePtr());
803 }
804
805 return INTEROP_RETURN(nullptr);
806}
807
808TypeRef GetIntegerTypeFromEnumType(ConstTypeRef enum_type) {
809 INTEROP_TRACE(enum_type);
810 if (!enum_type)
811 return INTEROP_RETURN(nullptr);
812
813 QualType QT = QualType::getFromOpaquePtr(enum_type.data);
814 if (const auto* ET = QT->getAs<EnumType>())
815 return INTEROP_RETURN(ET->getDecl()->getIntegerType().getAsOpaquePtr());
816
817 return INTEROP_RETURN(nullptr);
818}
819
820std::vector<DeclRef> GetEnumConstants(ConstDeclRef DRef) {
821 INTEROP_TRACE(DRef);
822 const auto* D = unwrap<clang::Decl>(DRef);
823
824 if (const auto* ED = llvm::dyn_cast_or_null<clang::EnumDecl>(D)) {
825 std::vector<DeclRef> enum_constants;
826 for (auto* ECD : ED->enumerators()) {
827 enum_constants.push_back(ECD);
828 }
829
830 return INTEROP_RETURN(enum_constants);
831 }
832
833 return INTEROP_RETURN(std::vector<DeclRef>{});
834}
835
836TypeRef GetEnumConstantType(ConstDeclRef DRef) {
837 INTEROP_TRACE(DRef);
838 if (!DRef)
839 return INTEROP_RETURN(nullptr);
840
841 const auto* D = unwrap<clang::Decl>(DRef);
842 if (const auto* ECD = llvm::dyn_cast<clang::EnumConstantDecl>(D))
843 return INTEROP_RETURN(ECD->getType().getAsOpaquePtr());
844
845 return INTEROP_RETURN(nullptr);
846}
847
848size_t GetEnumConstantValue(ConstDeclRef DRef) {
849 INTEROP_TRACE(DRef);
850 const auto* D = unwrap<clang::Decl>(DRef);
851 if (const auto* ECD = llvm::dyn_cast_or_null<clang::EnumConstantDecl>(D)) {
852 const llvm::APSInt& Val = ECD->getInitVal();
853 return INTEROP_RETURN(Val.getExtValue());
854 }
855 return INTEROP_RETURN(0);
856}
857
858size_t GetSizeOfType(ConstTypeRef TyRef) {
859 INTEROP_TRACE(TyRef);
860 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
861 if (const TagType* TT = QT->getAs<TagType>())
862 return INTEROP_RETURN(SizeOf(TT->getDecl()));
863
864 // FIXME: Can we get the size of a non-tag TyRef?
865 auto TI = getSema().getASTContext().getTypeInfo(QT);
866 size_t TypeSize = TI.Width;
867 return INTEROP_RETURN(TypeSize / 8);
868}
869
870bool IsVariable(ConstDeclRef DRef) {
871 INTEROP_TRACE(DRef);
872 const auto* D = unwrap<clang::Decl>(DRef);
873 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::VarDecl>(D));
874}
875
876std::string GetName(ConstDeclRef DRef) {
877 INTEROP_TRACE(DRef);
878 const auto* D = unwrap<clang::NamedDecl>(DRef);
879
880 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
881 return INTEROP_RETURN("");
882 }
883
884 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(D)) {
885 return INTEROP_RETURN(ND->getNameAsString());
886 }
887
888 return INTEROP_RETURN("<unnamed>");
889}
890
891static std::string GetCompleteNameImpl(ConstDeclRef DRef, bool qualified) {
892 auto& C = getSema().getASTContext();
893 const auto* D = unwrap<Decl>(DRef);
894
895 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(D)) {
896 PrintingPolicy Policy = C.getPrintingPolicy();
897 Policy.SuppressUnwrittenScope = true;
898 if (qualified) {
899 Policy.FullyQualifiedName = true;
900 Policy.Suppress_Elab = true;
901 } else {
902 Policy.SuppressScope = true;
903 Policy.AnonymousTagLocations = false;
904 Policy.SuppressTemplateArgsInCXXConstructors = false;
905 Policy.SuppressDefaultTemplateArgs = false;
906 Policy.AlwaysIncludeTypeForTemplateArgument = true;
907 }
908
909 if (const auto* TD = llvm::dyn_cast<TagDecl>(ND)) {
910 std::string type_name;
911 QualType QT = compat::GetTypeFromDecl(TD);
912 QT.getAsStringInternal(type_name, Policy);
913 return type_name;
914 }
915 if (const auto* FD = llvm::dyn_cast<FunctionDecl>(ND)) {
916 std::string func_name;
917 llvm::raw_string_ostream name_stream(func_name);
918 FD->getNameForDiagnostic(name_stream, Policy, qualified);
919 name_stream.flush();
920 return func_name;
921 }
922
923 return qualified ? ND->getQualifiedNameAsString() : ND->getNameAsString();
924 }
925
926 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
927 return "";
928 }
929
930 return "<unnamed>";
931}
932
933std::string GetCompleteName(ConstDeclRef DRef) {
934 INTEROP_TRACE(DRef);
935 return INTEROP_RETURN(GetCompleteNameImpl(DRef, /*qualified=*/false));
936}
937
938std::string GetQualifiedName(ConstDeclRef DRef) {
939 INTEROP_TRACE(DRef);
940 const auto* D = unwrap<Decl>(DRef);
941 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(D)) {
942 return INTEROP_RETURN(ND->getQualifiedNameAsString());
943 }
944
945 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
946 return INTEROP_RETURN("");
947 }
948
949 return INTEROP_RETURN("<unnamed>");
950}
951
952std::string GetQualifiedCompleteName(ConstDeclRef DRef) {
953 INTEROP_TRACE(DRef);
954 return INTEROP_RETURN(GetCompleteNameImpl(DRef, /*qualified=*/true));
955}
956
957std::string GetDoxygenComment(ConstDeclRef DRef, bool strip_comment_markers) {
958 INTEROP_TRACE(DRef, strip_comment_markers);
959 const auto* D = unwrap<Decl>(DRef);
960 if (!D)
961 return INTEROP_RETURN("");
962
963 D = D->getCanonicalDecl();
964 ASTContext& C = D->getASTContext();
965
966 const RawComment* RC = C.getRawCommentForAnyRedecl(D);
967 if (!RC)
968 return INTEROP_RETURN("");
969
970 (void)C.getCommentForDecl(D, /*PP=*/nullptr);
971
972 const SourceManager& SM = C.getSourceManager();
973
974 if (!strip_comment_markers)
975 return INTEROP_RETURN(RC->getRawText(SM).str());
976
977 return INTEROP_RETURN(RC->getFormattedText(SM, C.getDiagnostics()));
978}
979
980std::vector<DeclRef> GetUsingNamespaces(ConstDeclRef DRef) {
981 INTEROP_TRACE(DRef);
982 const auto* D = unwrap<clang::Decl>(DRef);
983
984 if (const auto* DC = llvm::dyn_cast_or_null<clang::DeclContext>(D)) {
985 std::vector<DeclRef> namespaces;
986 for (auto UD : DC->using_directives()) {
987 namespaces.push_back(UD->getNominatedNamespace());
988 }
989 return INTEROP_RETURN(namespaces);
990 }
991
992 return INTEROP_RETURN(std::vector<DeclRef>{});
993}
994
995DeclRef GetGlobalScope() {
997 return INTEROP_RETURN(
998 getSema().getASTContext().getTranslationUnitDecl()->getFirstDecl());
999}
1000
1001static Decl* GetScopeFromType(QualType QT) {
1002 if (auto* Type = QT.getCanonicalType().getTypePtrOrNull()) {
1003 Type = Type->getPointeeOrArrayElementType();
1004 Type = Type->getUnqualifiedDesugaredType();
1005 if (auto* ET = llvm::dyn_cast<EnumType>(Type))
1006 return ET->getDecl();
1007 CXXRecordDecl* CXXRD = Type->getAsCXXRecordDecl();
1008 if (CXXRD)
1009 return CXXRD->getCanonicalDecl();
1010 }
1011 return 0;
1012}
1013
1014DeclRef GetScopeFromType(ConstTypeRef TyRef) {
1015 INTEROP_TRACE(TyRef);
1016 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
1017 return INTEROP_RETURN(GetScopeFromType(QT));
1018}
1019
1020static const clang::Decl* GetUnderlyingScopeImpl(const clang::Decl* D) {
1021 if (const auto* TND = dyn_cast_or_null<TypedefNameDecl>(D)) {
1022 if (auto* Scope = GetScopeFromType(TND->getUnderlyingType()))
1023 D = Scope;
1024 } else if (const auto* USS = dyn_cast_or_null<UsingShadowDecl>(D)) {
1025 if (const auto* Scope = USS->getTargetDecl())
1026 D = Scope;
1027 }
1028
1029 return D->getCanonicalDecl();
1030}
1031
1032DeclRef GetUnderlyingScope(ConstDeclRef DRef) {
1033 INTEROP_TRACE(DRef);
1034 if (!DRef)
1035 return INTEROP_RETURN(nullptr);
1036 // Strip const at the API boundary: GetUnderlyingScope is a CONST
1037 // operation but returns a mutable DRef (callers may use the result
1038 // for further operations).
1039 return INTEROP_RETURN(const_cast<clang::Decl*>(
1040 GetUnderlyingScopeImpl(unwrap<clang::Decl>(DRef))));
1041}
1042
1043DeclRef GetScope(const std::string& name, ConstDeclRef parent) {
1044 INTEROP_TRACE(name, parent);
1045 // FIXME: GetScope should be replaced by a general purpose lookup
1046 // and filter function. The function should be like GetNamed but
1047 // also take in a filter parameter which determines which results
1048 // to pass back
1049 if (name == "")
1051
1052 auto* ND = unwrap<NamedDecl>(GetNamed(name, parent));
1053
1054 if (!ND || ND == (NamedDecl*)-1)
1055 return INTEROP_RETURN(nullptr);
1056
1057 if (llvm::isa<NamespaceDecl>(ND) || llvm::isa<RecordDecl>(ND) ||
1058 llvm::isa<ClassTemplateDecl>(ND) || llvm::isa<TypedefNameDecl>(ND) ||
1059 llvm::isa<TypeAliasTemplateDecl>(ND) || llvm::isa<TypeAliasDecl>(ND))
1060 return INTEROP_RETURN(ND->getCanonicalDecl());
1061
1062 return INTEROP_RETURN(nullptr);
1063}
1064
1065DeclRef GetScopeFromCompleteName(const std::string& name) {
1066 INTEROP_TRACE(name);
1067 std::string delim = "::";
1068 size_t start = 0;
1069 size_t end = name.find(delim);
1070 DeclRef curr_scope = nullptr;
1071 while (end != std::string::npos) {
1072 curr_scope = GetScope(name.substr(start, end - start), curr_scope);
1073 start = end + delim.length();
1074 end = name.find(delim, start);
1075 }
1076 return INTEROP_RETURN(GetScope(name.substr(start, end), curr_scope));
1077}
1078
1079// Sema::CurScope is private, but we need to reseat it briefly to drive
1080// Sema::LookupName at a synthesized point inside `Within`. The
1081// ALLOW_ACCESS/ACCESS pair from Sins.h gets us there without patching
1082// clang.
1083ALLOW_ACCESS(clang::Sema, CurScope, clang::Scope*);
1084
1085namespace {
1086// Mirror DC's enclosing namespace nesting as a chain of clang::Scope*
1087// rooted at S.TUScope, each Scope's entity set to the matching
1088// DeclContext. Sema::CppLookupName walks this chain via getParent() and
1089// reads using-directives off each entity's NamespaceDecl, so this is
1090// enough to make unqualified lookup honour `using namespace ...;`
1091// declared inside DC.
1092clang::Scope* BuildSyntheticScopeChain(clang::Sema& S, clang::DeclContext* DC) {
1093 if (!DC || DC->isTranslationUnit())
1094 return S.TUScope;
1095 auto* Parent = BuildSyntheticScopeChain(S, DC->getParent());
1096 auto* Mine = new clang::Scope(Parent, clang::Scope::DeclScope, S.Diags);
1097 Mine->setEntity(DC);
1098 return Mine;
1099}
1100
1101// RAII: build a synthetic DRef chain for `Within`, install it as
1102// Sema::CurScope, restore + delete on destruction. CppLookupName is
1103// read-only on Scope/Sema state (only getParent/getEntity/
1104// getLookupEntity/isDeclScope reads, plus a stack-local
1105// UnqualUsingDirectiveSet); freeing the synthetic scopes is the
1106// entire teardown — no ActOnPopScope needed because we never pushed
1107// any decl onto these scopes.
1108class SyntheticScopeChain {
1109public:
1110 SyntheticScopeChain(clang::Sema& Sema, clang::DeclContext* Within)
1111 : S(Sema), Innermost(BuildSyntheticScopeChain(Sema, Within)),
1112 Saved(ACCESS(Sema, CurScope)) {
1113 ACCESS(S, CurScope) = Innermost;
1114 }
1115 ~SyntheticScopeChain() {
1116 ACCESS(S, CurScope) = Saved;
1117 while (Innermost && Innermost != S.TUScope) {
1118 auto* Next = Innermost->getParent();
1119 delete Innermost;
1120 Innermost = Next;
1121 }
1122 }
1123 SyntheticScopeChain(const SyntheticScopeChain&) = delete;
1124 SyntheticScopeChain& operator=(const SyntheticScopeChain&) = delete;
1125
1126 clang::Scope* get() const { return Innermost; }
1127
1128private:
1129 clang::Sema& S;
1130 clang::Scope* Innermost;
1131 clang::Scope* Saved;
1132};
1133
1134// Unqualified lookup of `Name` from a synthesized point inside `Within`
1135// ([basic.lookup.unqual]). Honours using-directives reachable from
1136// Within, which Sema::LookupQualifiedName does not.
1137//
1138// FIXME: longer-term we want two distinct routes — one wrapping
1139// LookupQualifiedName and one this — exposed as separate operations so
1140// callers can pick the C++ semantics they actually want. For now
1141// GetNamed gates this behind a qualified-lookup-miss + reachable
1142// using-directive check, so the common case stays on the cheap path.
1143clang::NamedDecl* LookupUnqualified(clang::Sema& S,
1144 const clang::DeclarationName& Name,
1145 clang::DeclContext* Within) {
1146 SyntheticScopeChain Chain(S, Within);
1147 // NotForRedeclaration: ForVisibleRedeclaration causes Sema::CppLookupName
1148 // to return as soon as the innermost namespace doesn't directly contain
1149 // the name (SemaLookup.cpp:1545), which prevents using-directives from
1150 // an enclosing common-ancestor namespace from firing. We're doing
1151 // ordinary name lookup, not collecting redeclarations.
1152 clang::LookupResult R(S, Name, clang::SourceLocation(),
1153 clang::Sema::LookupOrdinaryName,
1154 RedeclarationKind::NotForRedeclaration);
1155 R.suppressDiagnostics();
1156 S.LookupName(R, Chain.get());
1157 // Match LookupResult2Decl from CppInterOpInterpreter.h (clang-repl-only
1158 // header, not included in CPPINTEROP_USE_CLING builds). Empty -> null;
1159 // single -> found decl; multi -> (D*)-1 sentinel that GetNamed treats
1160 // as "ambiguous, give up".
1161 if (R.empty())
1162 return nullptr;
1163 R.resolveKind();
1164 if (R.isSingleResult())
1165 return llvm::dyn_cast<clang::NamedDecl>(R.getFoundDecl());
1166 return (clang::NamedDecl*)-1;
1167}
1168
1169// Cheap probe: does any namespace from `DC` up to TU carry at least
1170// one using-directive? Gates the synthetic-DRef-chain build below so
1171// the common case (no using-directives anywhere on the path) doesn't
1172// pay the heap-allocation tax.
1173bool HasReachableUsingDirective(const clang::DeclContext* DC) {
1174 for (; DC && !DC->isTranslationUnit(); DC = DC->getParent()) {
1175 if (const auto* NS = llvm::dyn_cast<clang::NamespaceDecl>(DC)) {
1176 auto UDs = NS->using_directives();
1177 if (UDs.begin() != UDs.end())
1178 return true;
1179 }
1180 }
1181 return false;
1182}
1183} // namespace
1184
1185DeclRef GetNamed(const std::string& name, ConstDeclRef parent /*= nullptr*/) {
1186 INTEROP_TRACE(name, parent);
1187 clang::DeclContext* Within = 0;
1188 if (parent) {
1189 auto* D = unwrap<clang::Decl>(GetUnderlyingScope(parent));
1190 Within = llvm::dyn_cast<clang::DeclContext>(D);
1191 }
1192#ifdef CPPINTEROP_USE_CLING
1193 if (Within)
1194 Within->getPrimaryContext()->buildLookup();
1195#endif
1197
1198 // Fast path: qualified lookup. Cheap, no DRef-chain allocation, and
1199 // resolves every name not brought into `Within` via a using-directive.
1200 // Lookup::Named falls back to LookupName(R, TUScope) when Within is
1201 // null, so TU-level using-directives are already handled there.
1202 auto* ND = CppInternal::utils::Lookup::Named(&getSema(), name, Within);
1203 if (ND && ND != (clang::NamedDecl*)-1)
1204 return INTEROP_RETURN(ND->getCanonicalDecl());
1205
1206 // Slow path: only when qualified lookup missed AND `Within` is a
1207 // namespace whose enclosing chain carries at least one using-directive
1208 // (the only reason qualified-vs-unqualified disagree at namespace
1209 // DRef per [basic.lookup.unqual] vs [basic.lookup.qual]).
1210 if (!Within || !llvm::isa<clang::NamespaceDecl>(Within) ||
1211 !HasReachableUsingDirective(Within))
1212 return INTEROP_RETURN(nullptr);
1213 clang::DeclarationName DName = &getSema().Context.Idents.get(name);
1214 ND = LookupUnqualified(getSema(), DName, Within);
1215 if (ND && ND != (clang::NamedDecl*)-1)
1216 return INTEROP_RETURN(ND->getCanonicalDecl());
1217
1218 return INTEROP_RETURN(nullptr);
1219}
1220
1221DeclRef GetParentScope(ConstDeclRef DRef) {
1222 INTEROP_TRACE(DRef);
1223 // const_cast: the returned DeclRef is a mutable DRef, so the caller may
1224 // mutate the AST. Walking parents is logically const, but the return TyRef
1225 // is the mutable DRef.
1226 auto* D = const_cast<Decl*>(unwrap<clang::Decl>(DRef));
1227
1228 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
1229 return INTEROP_RETURN(nullptr);
1230 }
1231 auto* ParentDC = D->getDeclContext();
1232
1233 if (!ParentDC)
1234 return INTEROP_RETURN(nullptr);
1235
1236 auto* P = clang::Decl::castFromDeclContext(ParentDC)->getCanonicalDecl();
1237
1238 if (auto* TU = llvm::dyn_cast_or_null<TranslationUnitDecl>(P))
1239 return INTEROP_RETURN(TU->getFirstDecl());
1240
1241 return INTEROP_RETURN(P);
1242}
1243
1244size_t GetNumBases(ConstDeclRef DRef) {
1245 INTEROP_TRACE(DRef);
1246 const auto* D = unwrap<Decl>(DRef);
1247
1248 if (const auto* CTSD =
1249 llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(D))
1250 if (!CTSD->hasDefinition())
1252 getInterp(), const_cast<ClassTemplateSpecializationDecl*>(CTSD));
1253 if (const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1254 if (CXXRD->hasDefinition())
1255 return INTEROP_RETURN(CXXRD->getNumBases());
1256 }
1257
1258 return INTEROP_RETURN(0);
1259}
1260
1261DeclRef GetBaseClass(ConstDeclRef DRef, size_t ibase) {
1262 INTEROP_TRACE(DRef, ibase);
1263 const auto* D = unwrap<Decl>(DRef);
1264 const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D);
1265 if (!CXXRD || CXXRD->getNumBases() <= ibase)
1266 return INTEROP_RETURN(nullptr);
1267
1268 auto TyRef = (CXXRD->bases_begin() + ibase)->getType();
1269 if (const auto* RT = TyRef->getAs<RecordType>())
1270 return INTEROP_RETURN(RT->getDecl()->getCanonicalDecl());
1271
1272 return INTEROP_RETURN(nullptr);
1273}
1274
1275// FIXME: Consider dropping this interface as it seems the same as
1276// IsTypeDerivedFrom.
1277bool IsSubclass(ConstDeclRef derived, ConstDeclRef base) {
1278 INTEROP_TRACE(derived, base);
1279 if (derived == base)
1280 return INTEROP_RETURN(true);
1281
1282 if (!derived || !base)
1283 return INTEROP_RETURN(false);
1284
1285 const auto* derived_D = unwrap<clang::Decl>(derived);
1286 const auto* base_D = unwrap<clang::Decl>(base);
1287
1288 if (!isa<CXXRecordDecl>(derived_D) || !isa<CXXRecordDecl>(base_D))
1289 return INTEROP_RETURN(false);
1290
1291 const auto* Derived = cast<CXXRecordDecl>(derived_D);
1292 const auto* Base = cast<CXXRecordDecl>(base_D);
1293 return INTEROP_RETURN(
1295}
1296
1297// Copied from VTableBuilder.cpp
1298// This is an internal helper function for the CppInterOp library (as evident
1299// by the 'static' declaration), while the similar GetBaseClassOffset()
1300// function below is exposed to library users.
1301static unsigned ComputeBaseOffset(const ASTContext& Context,
1302 const CXXRecordDecl* DerivedRD,
1303 const CXXBasePath& Path) {
1304 CharUnits NonVirtualOffset = CharUnits::Zero();
1305
1306 unsigned NonVirtualStart = 0;
1307 const CXXRecordDecl* VirtualBase = nullptr;
1308
1309 // First, look for the virtual base class.
1310 for (int I = Path.size(), E = 0; I != E; --I) {
1311 const CXXBasePathElement& Element = Path[I - 1];
1312
1313 if (Element.Base->isVirtual()) {
1314 NonVirtualStart = I;
1315 QualType VBaseType = Element.Base->getType();
1316 VirtualBase = VBaseType->getAsCXXRecordDecl();
1317 break;
1318 }
1319 }
1320
1321 // Now compute the non-virtual offset.
1322 for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
1323 const CXXBasePathElement& Element = Path[I];
1324
1325 // Check the base class offset.
1326 const ASTRecordLayout& Layout = Context.getASTRecordLayout(Element.Class);
1327
1328 const CXXRecordDecl* Base = Element.Base->getType()->getAsCXXRecordDecl();
1329
1330 NonVirtualOffset += Layout.getBaseClassOffset(Base);
1331 }
1332
1333 // FIXME: This should probably use CharUnits or something. Maybe we should
1334 // even change the base offsets in ASTRecordLayout to be specified in
1335 // CharUnits.
1336 // return BaseOffset(DerivedRD, VirtuaBose, aBlnVirtualOffset);
1337 if (VirtualBase) {
1338 const ASTRecordLayout& Layout = Context.getASTRecordLayout(DerivedRD);
1339 CharUnits VirtualOffset = Layout.getVBaseClassOffset(VirtualBase);
1340 return (NonVirtualOffset + VirtualOffset).getQuantity();
1341 }
1342 return NonVirtualOffset.getQuantity();
1343}
1344
1345int64_t GetBaseClassOffset(ConstDeclRef derived, ConstDeclRef base) {
1346 INTEROP_TRACE(derived, base);
1347 if (base == derived)
1348 return INTEROP_RETURN(0);
1349
1350 assert(derived || base);
1351
1352 const auto* DD = unwrap<Decl>(derived);
1353 const auto* BD = unwrap<Decl>(base);
1354 if (!isa<CXXRecordDecl>(DD) || !isa<CXXRecordDecl>(BD))
1355 return INTEROP_RETURN(-1);
1356 const auto* DCXXRD = cast<CXXRecordDecl>(DD);
1357 const auto* BCXXRD = cast<CXXRecordDecl>(BD);
1358 // GCC's -Wmaybe-uninitialized false-positives here only under ASan:
1359 // -fsanitize=address keeps the SmallDenseMap's union storage live across
1360 // poison/unpoison calls and blocks the SROA pass that normally folds away
1361 // the LargeRep read on the Small==true branch. The load survives into the
1362 // IR the uninit pass sees, and it can no longer prove the `Small` guard.
1363 // Clang's analyzer does not false-positive here; plain-O2 GCC does not
1364 // either. Narrow the suppression to GCC + ASan.
1365#if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
1366#pragma GCC diagnostic push
1367#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1368#endif
1369 CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
1370 /*DetectVirtual=*/false);
1371#if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
1372#pragma GCC diagnostic pop
1373#endif
1374 DCXXRD->isDerivedFrom(BCXXRD, Paths);
1375
1376 // FIXME: We might want to cache these requests as they seem expensive.
1377 return INTEROP_RETURN(
1378 ComputeBaseOffset(getSema().getASTContext(), DCXXRD, Paths.front()));
1379}
1380
1381template <typename DeclType, typename HandleType>
1382static void GetClassDecls(ConstDeclRef DRef, std::vector<HandleType>& methods) {
1383 if (!DRef)
1384 return;
1385
1386 // Unwrap to mutable: ForceDeclarationOfImplicitMembers is a lazy-init
1387 // operation on the AST, logically const for the caller.
1388 Decl* D = const_cast<Decl*>(unwrap<clang::Decl>(DRef));
1389
1390 if (auto* TD = dyn_cast<TypedefNameDecl>(D)) {
1391 DeclRef Scope = GetScopeFromType(TD->getUnderlyingType());
1392 D = unwrap<clang::Decl>(Scope);
1393 }
1394
1395 if (!D || !isa<CXXRecordDecl>(D))
1396 return;
1397
1398 auto* CXXRD = dyn_cast<CXXRecordDecl>(D);
1400 if (auto* CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
1401 QualType QT = compat::GetTypeFromDecl(CTSD);
1402 if (!getSema().isCompleteType(CTSD->getLocation(), QT))
1403 return; // Unsuccesfull instantiaton
1404 }
1405
1406 if (CXXRD->hasDefinition())
1407 CXXRD = CXXRD->getDefinition();
1408 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1409 for (Decl* DI : CXXRD->decls()) {
1410 if (auto* MD = dyn_cast<DeclType>(DI))
1411 methods.push_back(MD);
1412 else if (auto* USD = dyn_cast<UsingShadowDecl>(DI)) {
1413 auto* MD = dyn_cast<DeclType>(USD->getTargetDecl());
1414 if (!MD)
1415 continue;
1416
1417 auto* CUSD = dyn_cast<ConstructorUsingShadowDecl>(DI);
1418 if (!CUSD) {
1419 methods.push_back(MD);
1420 continue;
1421 }
1422
1423 auto* CXXCD = dyn_cast_or_null<CXXConstructorDecl>(CUSD->getTargetDecl());
1424 if (!CXXCD) {
1425 methods.push_back(MD);
1426 continue;
1427 }
1428 if (CXXCD->isDeleted())
1429 continue;
1430
1431 // Result is appended to the decls, i.e. CXXRD, iterator
1432 // non-shadowed decl will be push_back later
1433 // methods.push_back(Result);
1434 getSema().findInheritingConstructor(SourceLocation(), CXXCD, CUSD);
1435 }
1436 }
1437}
1438
1439void GetClassMethods(ConstDeclRef DRef, std::vector<FuncRef>& methods) {
1440 INTEROP_TRACE(DRef, INTEROP_OUT(methods));
1441 GetClassDecls<CXXMethodDecl>(DRef, methods);
1442 return INTEROP_VOID_RETURN();
1443}
1444
1445void GetFunctionTemplatedDecls(ConstDeclRef DRef,
1446 std::vector<FuncRef>& methods) {
1447 INTEROP_TRACE(DRef, INTEROP_OUT(methods));
1448 GetClassDecls<FunctionTemplateDecl>(DRef, methods);
1449 return INTEROP_VOID_RETURN();
1450}
1451
1452bool HasDefaultConstructor(ConstDeclRef DRef) {
1453 INTEROP_TRACE(DRef);
1454 const auto* D = unwrap<clang::Decl>(DRef);
1455
1456 if (const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D))
1457 return INTEROP_RETURN(CXXRD->hasDefaultConstructor());
1458
1459 return INTEROP_RETURN(false);
1460}
1461
1462FuncRef GetDefaultConstructor(compat::Interpreter& interp, DeclRef DRef) {
1463 if (!HasDefaultConstructor(DRef))
1464 return nullptr;
1465
1466 auto* CXXRD = unwrap<clang::CXXRecordDecl>(DRef);
1468 return interp.getCI()->getSema().LookupDefaultConstructor(CXXRD);
1469}
1470
1471FuncRef GetDefaultConstructor(DeclRef DRef) {
1472 INTEROP_TRACE(DRef);
1474}
1475
1476FuncRef GetDestructor(ConstDeclRef DRef) {
1477 INTEROP_TRACE(DRef);
1478 // ForceDeclarationOfImplicitMembers is a lazy-init operation.
1479 auto* D = const_cast<Decl*>(unwrap<clang::Decl>(DRef));
1480
1481 if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1482 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1483 return INTEROP_RETURN(CXXRD->getDestructor());
1484 }
1485
1486 return INTEROP_RETURN(nullptr);
1487}
1488
1489void DumpScope(ConstDeclRef DRef) {
1490 INTEROP_TRACE(DRef);
1491 const auto* D = unwrap<clang::Decl>(DRef);
1492 D->dump();
1493 return INTEROP_VOID_RETURN();
1494}
1495
1496// Map an operator spelling (e.g. "operator==") to the CXXOperatorName its
1497// overloads are stored under, since identifier lookup never matches them.
1498// Returns an empty DeclarationName for non-operators (e.g. "operators_count"),
1499// leaving the caller on the identifier path. We can't use LookupOperatorName
1500// for this: it ignores class members, which this entry point must also find.
1501static DeclarationName getCXXOperatorDeclName(ASTContext& Ctx,
1502 llvm::StringRef name) {
1503 static constexpr llvm::StringRef OperatorPrefix("operator");
1504 if (!name.consume_front(OperatorPrefix) || name.empty() ||
1505 clang::isAsciiIdentifierContinue(
1506 static_cast<unsigned char>(name.front())))
1507 return DeclarationName();
1508
1509 llvm::StringRef Spelling = name.trim();
1510#define OVERLOADED_OPERATOR(OpName, OpSpelling, Token, Unary, Binary, \
1511 MemberOnly) \
1512 if (Spelling == (OpSpelling)) \
1513 return Ctx.DeclarationNames.getCXXOperatorName(clang::OO_##OpName);
1514#include "clang/Basic/OperatorKinds.def"
1515#undef OVERLOADED_OPERATOR
1516 return DeclarationName();
1517}
1518
1519std::vector<FuncRef> GetFunctionsUsingName(ConstDeclRef DRef,
1520 const std::string& name) {
1521 INTEROP_TRACE(DRef, name);
1522
1523 if (!DRef || name.empty())
1524 return INTEROP_RETURN(std::vector<FuncRef>{});
1525
1526 const auto* D = unwrap<Decl>(GetUnderlyingScope(DRef));
1527
1528 std::vector<FuncRef> funcs;
1529 auto& S = getSema();
1530 auto& Ctx = getASTContext();
1531
1532 DeclarationName DName = getCXXOperatorDeclName(Ctx, name);
1533 if (!DName)
1534 DName = &Ctx.Idents.get(name);
1535
1536 clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
1537 RedeclarationKind::ForVisibleRedeclaration);
1538
1539 CppInternal::utils::Lookup::Named(&S, R, Decl::castToDeclContext(D));
1540
1541 if (R.empty())
1542 return INTEROP_RETURN(funcs);
1543
1544 R.resolveKind();
1545
1546 for (auto* Found : R) {
1547 if (llvm::isa<FunctionDecl>(Found))
1548 funcs.push_back(Found);
1549 else if (auto* USD = llvm::dyn_cast<UsingShadowDecl>(Found)) {
1550 if (auto* FTD = llvm::dyn_cast<FunctionDecl>(USD->getTargetDecl()))
1551 funcs.push_back(FTD);
1552 }
1553 }
1554
1555 return INTEROP_RETURN(funcs);
1556}
1557
1558TypeRef GetFunctionReturnType(ConstFuncRef func) {
1559 INTEROP_TRACE(func);
1560 const auto* D = unwrap<clang::Decl>(func);
1561 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D)) {
1562 QualType Type = FD->getReturnType();
1563 if (Type->isUndeducedAutoType()) {
1564 bool needInstantiation = false;
1565 if (IsTemplatedFunction(FD) && !FD->isDefined())
1566 needInstantiation = true;
1567 if (const auto* MD = llvm::dyn_cast<clang::CXXMethodDecl>(FD)) {
1568 if (IsTemplateSpecialization(MD->getParent()))
1569 needInstantiation = true;
1570 }
1571
1572 if (needInstantiation) {
1573 // Lazy AST instantiation — logically const for the caller.
1575 const_cast<Decl*>(static_cast<const Decl*>(FD)));
1576 }
1577 Type = FD->getReturnType();
1578 }
1579 return INTEROP_RETURN(Type.getAsOpaquePtr());
1580 }
1581
1582 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1583 return INTEROP_RETURN(
1584 (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr());
1585
1586 return INTEROP_RETURN(nullptr);
1587}
1588
1589bool IsAllocator(ConstFuncRef Fn) {
1590 INTEROP_TRACE(Fn);
1591 if (!Fn)
1592 return INTEROP_RETURN(false);
1593 const auto* D = unwrap<clang::Decl>(Fn);
1594 if (const auto* FD = dyn_cast<FunctionDecl>(D)) {
1595 if (FD->getBuiltinID() == Builtin::ID::BImalloc)
1596 return INTEROP_RETURN(true);
1597 if (const auto* FDA = FD->getAttr<RestrictAttr>()) {
1598 if (FDA->getSemanticSpelling() != RestrictAttr::Declspec_restrict)
1599 return INTEROP_RETURN(true);
1600 }
1601
1602 if (const auto* FDA = FD->getAttr<OwnershipAttr>()) {
1603 if (FDA->getOwnKind() == OwnershipAttr::Returns)
1604 return INTEROP_RETURN(true);
1605 }
1606
1607 if (FD->hasAttr<CFReturnsRetainedAttr>() ||
1608 FD->hasAttr<NSReturnsRetainedAttr>() ||
1609 FD->hasAttr<OSReturnsRetainedAttr>())
1610 return INTEROP_RETURN(true);
1611 }
1612
1613 return INTEROP_RETURN(false);
1614}
1615
1616bool IsDeallocator(ConstFuncRef Fn) {
1617 INTEROP_TRACE(Fn);
1618 if (!Fn)
1619 INTEROP_RETURN(false);
1620 const auto* D = unwrap<clang::Decl>(Fn);
1621 if (const auto* FD = dyn_cast<FunctionDecl>(D)) {
1622 if (FD->getBuiltinID() == Builtin::ID::BIfree)
1623 return INTEROP_RETURN(true);
1624 if (const auto* FDA = FD->getAttr<OwnershipAttr>()) {
1625 if (FDA->getOwnKind() == OwnershipAttr::Takes)
1626 return INTEROP_RETURN(true);
1627 }
1628 }
1629
1630 return INTEROP_RETURN(false);
1631}
1632
1633bool IsFunctionProtoType(ConstTypeRef TyRef) {
1634 INTEROP_TRACE(TyRef);
1635 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
1636 const auto* T = QT.getTypePtr();
1637 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::FunctionProtoType>(T));
1638}
1639
1640static std::optional<AllocType>
1641AnalyzeAllocType(const clang::FunctionDecl* Fn,
1642 std::unordered_map<const clang::FunctionDecl*,
1643 std::optional<AllocType>>& visitedFuncs);
1644
1645namespace {
1646struct AllocationTraverser : RecursiveASTVisitor<AllocationTraverser> {
1647 std::unordered_map<const clang::VarDecl*, std::optional<AllocType>> varMap;
1648 std::unordered_map<const clang::FunctionDecl*, std::optional<AllocType>>&
1650 // Result var keeps the combination all possible values of previous return
1651 // statements
1652 std::optional<AllocType> result;
1653
1654 AllocationTraverser(std::unordered_map<const clang::FunctionDecl*,
1655 std::optional<AllocType>>& cache)
1656 : visitedFuncs(cache) {}
1657
1658 // Do not analyze lambda functions' bodies.
1659 bool TraverseLambdaExpr(clang::LambdaExpr*) { return true; }
1660
1661 // Do not analyze inside of TagDecls(structs/unions/class)
1662 bool TraverseDecl(clang::Decl* D) {
1663 if (llvm::isa_and_nonnull<clang::TagDecl>(D))
1664 return true;
1665 return RecursiveASTVisitor::TraverseDecl(D);
1666 }
1667
1668 bool VisitVarDecl(VarDecl* VD) {
1669 Expr* expr = VD->getInit();
1670 if (expr)
1671 varMap[VD] = handleExpr(expr);
1672 else
1673 varMap[VD] = AllocType::None;
1674 return true;
1675 }
1676
1677 bool VisitBinaryOperator(clang::BinaryOperator* BO) {
1678 if (BO->getOpcode() != BO_Assign)
1679 return true;
1680 Expr* LHS = BO->getLHS();
1681 LHS = LHS->IgnoreParenCasts();
1682 if (auto* DRE = dyn_cast<DeclRefExpr>(LHS)) {
1683 if (auto* VD = dyn_cast<VarDecl>(DRE->getDecl())) {
1684 Expr* RHS = BO->getRHS();
1685 varMap[VD] = handleExpr(RHS);
1686 }
1687 }
1688 return true;
1689 }
1690
1691 bool VisitReturnStmt(ReturnStmt* RS) {
1692 const clang::Expr* retExpr = RS->getRetValue();
1693 // Tmp is current return statement's AllocType value, result is combination
1694 // of previous return statements
1695 std::optional<AllocType> tmp = handleExpr(retExpr);
1696 if (!tmp.has_value())
1697 return true;
1698 if (!result.has_value())
1699 result = tmp;
1700 // If function's allocation behaviour differs between different cases,
1701 // analyzer returns unknown.
1702 else if (*result != tmp) {
1703 result = AllocType::Unknown;
1704 return false;
1705 }
1706 return true;
1707 }
1708
1709 std::optional<AllocType> handleCall(const clang::CallExpr* CE) {
1710 if (const auto* FD = CE->getDirectCallee()) {
1711 if (FD->getBuiltinID() == Builtin::ID::BImalloc)
1712 return AllocType::Malloc;
1713 auto it = visitedFuncs.find(FD);
1714 if (it == visitedFuncs.end()) {
1715 visitedFuncs[FD] = std::nullopt;
1716 return AnalyzeAllocType(FD, visitedFuncs);
1717 }
1718 return it->second;
1719 }
1720 // Function pointer calle
1721 return AllocType::Unknown;
1722 }
1723
1724 static AllocType handleNew(const clang::CXXNewExpr* CNE) {
1725 if (CNE->getNumPlacementArgs() > 0)
1726 return AllocType::None;
1727 if (CNE->isArray())
1728 return AllocType::NewArr;
1729 return AllocType::New;
1730 }
1731
1732 std::optional<AllocType> handleExpr(const clang::Expr* expr) {
1733 const clang::Expr* finExpr = expr->IgnoreParenCasts();
1734 // Case: return new __type__
1735 if (const auto* CNE = dyn_cast<CXXNewExpr>(finExpr))
1736 return handleNew(CNE);
1737
1738 // Case: returns a variable
1739 if (const auto* DRE = dyn_cast<DeclRefExpr>(finExpr)) {
1740 if (const auto* VD = dyn_cast<VarDecl>(DRE->getDecl())) {
1741 auto it = varMap.find(VD);
1742 if (it != varMap.end())
1743 return it->second;
1744 }
1745 // FIXME: BindingDecl, NonTypeTemplateParmDecl are not handled
1746 return AllocType::None;
1747 }
1748
1749 // Case: malloc or another func call
1750 if (const auto* CE = dyn_cast<CallExpr>(finExpr))
1751 return handleCall(CE);
1752 return AllocType::None;
1753 }
1754};
1755} // namespace
1756
1757static std::optional<AllocType>
1758AnalyzeAllocType(const clang::FunctionDecl* Fn,
1759 std::unordered_map<const clang::FunctionDecl*,
1760 std::optional<AllocType>>& visitedFuncs) {
1761 const clang::QualType QT = Fn->getReturnType();
1762 if (!QT->isPointerType())
1763 return AllocType::None;
1764 const Stmt* fnBody = Fn->getBody();
1765 if (!fnBody)
1766 return AllocType::Unknown;
1767 const auto* CmpStmt = dyn_cast<clang::CompoundStmt>(fnBody);
1768 // FIXME:: try catch blocks are not CompoundStmt, only edge case
1769 if (!CmpStmt)
1770 return AllocType::Unknown;
1771 AllocationTraverser Traverser(visitedFuncs);
1772 Traverser.TraverseStmt(const_cast<clang::CompoundStmt*>(CmpStmt));
1773 auto res = Traverser.result;
1774 visitedFuncs[Fn] = res;
1775 return res;
1776}
1777
1778AllocType GetAllocType(ConstFuncRef Fn) {
1779 INTEROP_TRACE(Fn);
1780 if (Fn) {
1781 const auto* D = unwrap<Decl>(Fn);
1782 if (const auto* FD = dyn_cast<FunctionDecl>(D)) {
1783 std::unordered_map<const clang::FunctionDecl*, std::optional<AllocType>>
1785 visitedFuncs[FD] = std::nullopt;
1786 return INTEROP_RETURN(
1787 AnalyzeAllocType(FD, visitedFuncs).value_or(AllocType::None));
1788 }
1789 }
1790 return INTEROP_RETURN(AllocType::None);
1791}
1792
1793void GetFnTypeSignature(ConstTypeRef fn_type, std::vector<TypeRef>& sig) {
1794 INTEROP_TRACE(fn_type, INTEROP_OUT(sig));
1795 QualType QT = QualType::getFromOpaquePtr(fn_type.data);
1796 const auto* FPT = QT->getAs<clang::FunctionProtoType>();
1797 if (!FPT)
1798 return INTEROP_VOID_RETURN();
1799 sig.push_back(FPT->getReturnType().getAsOpaquePtr());
1800 for (size_t i = 0; i < FPT->getNumParams(); i++)
1801 sig.push_back(FPT->getParamType(i).getAsOpaquePtr());
1802 return INTEROP_VOID_RETURN();
1803}
1804
1805// A C++23 explicit object parameter (the `this Self self` of a "deducing this"
1806// member function) is a real ParmVarDecl, but it binds to the object the method
1807// is invoked on rather than being callee-supplied. Clang's getNumParams() /
1808// getMinRequiredArguments() count it; the *NonObject* / *Explicit* variants
1809// exclude it, which is what callers introspecting the argument list want.
1810size_t GetFunctionNumArgs(ConstFuncRef func) {
1811 INTEROP_TRACE(func);
1812 const auto* D = unwrap<clang::Decl>(func);
1813 if (const auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1814 return INTEROP_RETURN(FD->getNumNonObjectParams());
1815
1816 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1817 return INTEROP_RETURN(FD->getTemplatedDecl()->getNumNonObjectParams());
1818
1819 return INTEROP_RETURN(0);
1820}
1821
1822size_t GetFunctionRequiredArgs(ConstFuncRef func) {
1823 INTEROP_TRACE(func);
1824 const auto* D = unwrap<clang::Decl>(func);
1825 if (const auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1826 return INTEROP_RETURN(FD->getMinRequiredExplicitArguments());
1827
1828 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1829 return INTEROP_RETURN(
1830 FD->getTemplatedDecl()->getMinRequiredExplicitArguments());
1831
1832 return INTEROP_RETURN(0);
1833}
1834
1835TypeRef GetFunctionArgType(ConstFuncRef func, size_t iarg) {
1836 INTEROP_TRACE(func, iarg);
1837 const auto* D = unwrap<clang::Decl>(func);
1838
1839 if (const auto* FTD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1840 D = FTD->getTemplatedDecl();
1841
1842 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D)) {
1843 if (iarg < FD->getNumNonObjectParams()) {
1844 const auto* PVD = FD->getNonObjectParameter(iarg);
1845 return INTEROP_RETURN(PVD->getOriginalType().getAsOpaquePtr());
1846 }
1847 }
1848
1849 return INTEROP_RETURN(nullptr);
1850}
1851
1852bool IsTemplateParmType(ConstTypeRef TyRef) {
1853 INTEROP_TRACE(TyRef);
1854 clang::QualType QT = clang::QualType::getFromOpaquePtr(TyRef.data);
1855 return INTEROP_RETURN(QT->isTemplateTypeParmType());
1856}
1857
1858std::string GetFunctionSignature(ConstFuncRef func) {
1859 INTEROP_TRACE(func);
1860 if (!func)
1861 return INTEROP_RETURN("<unknown>");
1862
1863 const auto* D = unwrap<clang::Decl>(func);
1864 const clang::FunctionDecl* FD;
1865
1866 if (llvm::dyn_cast<FunctionDecl>(D))
1867 FD = llvm::dyn_cast<FunctionDecl>(D);
1868 else if (const auto* FTD = llvm::dyn_cast<clang::FunctionTemplateDecl>(D))
1869 FD = FTD->getTemplatedDecl();
1870 else
1871 return INTEROP_RETURN("<unknown>");
1872
1873 std::string Signature;
1874 raw_string_ostream SS(Signature);
1875 PrintingPolicy Policy = getASTContext().getPrintingPolicy();
1876 // Skip printing the body
1877 Policy.TerseOutput = true;
1878 Policy.FullyQualifiedName = true;
1879 Policy.SuppressDefaultTemplateArgs = false;
1880 FD->print(SS, Policy);
1881 SS.flush();
1882 return INTEROP_RETURN(Signature);
1883}
1884
1885// Internal functions that are not needed outside the library are
1886// encompassed in an anonymous namespace as follows.
1887namespace {
1888bool IsTemplatedFunction(const Decl* D) {
1889 return llvm::isa_and_nonnull<FunctionTemplateDecl>(D);
1890}
1891
1892bool IsTemplateInstantiationOrSpecialization(const Decl* D) {
1893 if (const auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
1894 auto TK = FD->getTemplatedKind();
1895 return TK ==
1896 FunctionDecl::TemplatedKind::TK_FunctionTemplateSpecialization ||
1897 TK == FunctionDecl::TemplatedKind::
1898 TK_DependentFunctionTemplateSpecialization ||
1899 TK == FunctionDecl::TemplatedKind::TK_FunctionTemplate;
1900 }
1901
1902 return false;
1903}
1904} // namespace
1905
1906bool IsFunctionDeleted(ConstFuncRef function) {
1907 INTEROP_TRACE(function);
1908 const auto* FD = cast<FunctionDecl>(unwrap<clang::Decl>(function));
1909 return INTEROP_RETURN(FD->isDeleted());
1910}
1911
1912bool IsTemplatedFunction(ConstFuncRef func) {
1913 INTEROP_TRACE(func);
1914 const auto* D = unwrap<Decl>(func);
1916 IsTemplateInstantiationOrSpecialization(D));
1917}
1918
1919// FIXME: This lookup is broken, and should no longer be used in favour of
1920// `GetClassTemplatedMethods` If the candidate set returned is =1, that means
1921// the template function exists and >1 means overloads
1922bool ExistsFunctionTemplate(const std::string& name, ConstDeclRef parent) {
1923 INTEROP_TRACE(name, parent);
1924 const DeclContext* Within = nullptr;
1925 if (parent) {
1926 const auto* D = unwrap<Decl>(parent);
1927 Within = llvm::dyn_cast<DeclContext>(D);
1928 }
1929
1930 auto* ND = CppInternal::utils::Lookup::Named(&getSema(), name, Within);
1931
1932 if ((intptr_t)ND == (intptr_t)0)
1933 return INTEROP_RETURN(false);
1934
1935 if ((intptr_t)ND != (intptr_t)-1)
1937 IsTemplateInstantiationOrSpecialization(ND));
1938
1939 // FIXME: Cycle through the Decls and check if there is a templated function
1940 return INTEROP_RETURN(true);
1941}
1942
1943// Looks up all constructors in the current DeclContext
1944void LookupConstructors(const std::string& name, ConstDeclRef parent,
1945 std::vector<FuncRef>& funcs) {
1946 INTEROP_TRACE(name, parent, INTEROP_OUT(funcs));
1947 // ForceDeclarationOfImplicitMembers / LookupConstructors are lazy-init ops.
1948 auto* D = const_cast<Decl*>(unwrap<Decl>(parent));
1949
1950 if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1951 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1952 DeclContextLookupResult Result = getSema().LookupConstructors(CXXRD);
1953 // Obtaining all constructors when we intend to lookup a method under a
1954 // DRef can lead to crashes. We avoid that by accumulating constructors
1955 // only if the Decl matches the lookup name.
1956 for (auto* i : Result)
1957 if (GetName(DeclRef(i)) == name)
1958 funcs.push_back(i);
1959 }
1960 return INTEROP_VOID_RETURN();
1961}
1962
1963bool GetClassTemplatedMethods(const std::string& name, ConstDeclRef parent,
1964 std::vector<FuncRef>& funcs) {
1965 INTEROP_TRACE(name, parent, INTEROP_OUT(funcs));
1966 const auto* D = unwrap<Decl>(parent);
1967 if (!D && name.empty())
1968 return INTEROP_RETURN(false);
1969
1970 // Accumulate constructors
1971 LookupConstructors(name, parent, funcs);
1972 auto& S = getSema();
1973 auto* DU = unwrap<Decl>(GetUnderlyingScope(parent));
1974 llvm::StringRef Name(name);
1975 DeclarationName DName = &getASTContext().Idents.get(name);
1976 clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
1977 RedeclarationKind::ForVisibleRedeclaration);
1978 auto* DC = clang::Decl::castToDeclContext(DU);
1980
1981 if (R.getResultKind() == clang_LookupResult_Not_Found && funcs.empty())
1982 return INTEROP_RETURN(false);
1983
1984 // Distinct match, single Decl
1985 else if (R.getResultKind() == clang_LookupResult_Found) {
1986 if (IsTemplatedFunction(R.getFoundDecl()))
1987 funcs.push_back(R.getFoundDecl());
1988 }
1989 // Loop over overload set
1990 else if (R.getResultKind() == clang_LookupResult_Found_Overloaded) {
1991 for (auto* Found : R) {
1992 if (IsTemplatedFunction(Found))
1993 funcs.push_back(Found);
1994 else if (auto* USD = llvm::dyn_cast<UsingShadowDecl>(Found)) {
1995 if (auto* FTD =
1996 llvm::dyn_cast<FunctionTemplateDecl>(USD->getTargetDecl()))
1997 funcs.push_back(FTD);
1998 }
1999 }
2000 }
2001
2002 // TODO: Handle ambiguously found LookupResult
2003 // else if (R.getResultKind() == clang::LookupResult::Ambiguous) {
2004 // auto kind = R.getAmbiguityKind();
2005 // ...
2006 // Produce a diagnostic describing the ambiguity that resulted
2007 // from name lookup as done in Sema::DiagnoseAmbiguousLookup
2008 //
2009 return INTEROP_RETURN(!funcs.empty());
2010}
2011
2012// Adapted from inner workings of Sema::BuildCallExpr
2013FuncRef
2014BestOverloadFunctionMatch(const std::vector<FuncRef>& candidates,
2015 const std::vector<TemplateArgInfo>& explicit_types,
2016 const std::vector<TemplateArgInfo>& arg_types) {
2017 INTEROP_TRACE(candidates, explicit_types, arg_types);
2018 auto& S = getSema();
2019 auto& C = S.getASTContext();
2020
2022
2023 // The overload resolution interfaces in Sema require a list of expressions.
2024 // However, unlike handwritten C++, we do not always have a expression.
2025 // Here we synthesize a placeholder expression to be able to use
2026 // Sema::AddOverloadCandidate. Made up expressions are fine because the
2027 // interface uses the list size and the expression types.
2028 struct WrapperExpr : public OpaqueValueExpr {
2029 WrapperExpr() : OpaqueValueExpr(clang::Stmt::EmptyShell()) {}
2030 };
2031 auto* Exprs = new WrapperExpr[arg_types.size()];
2032 llvm::SmallVector<Expr*> Args;
2033 Args.reserve(arg_types.size());
2034 size_t idx = 0;
2035 for (auto i : arg_types) {
2036 QualType Type = QualType::getFromOpaquePtr(i.m_Type);
2037 // XValue is an object that can be "moved" whereas PRValue is temporary
2038 // value. This enables overloads that require the object to be moved
2039 ExprValueKind ExprKind = ExprValueKind::VK_XValue;
2040 if (Type->isLValueReferenceType())
2041 ExprKind = ExprValueKind::VK_LValue;
2042
2043 new (&Exprs[idx]) OpaqueValueExpr(SourceLocation::getFromRawEncoding(1),
2044 Type.getNonReferenceType(), ExprKind);
2045 Args.push_back(&Exprs[idx]);
2046 ++idx;
2047 }
2048
2049 // Create a list of template arguments.
2050 llvm::SmallVector<TemplateArgument> TemplateArgs;
2051 TemplateArgs.reserve(explicit_types.size());
2052 for (auto explicit_type : explicit_types) {
2053 QualType ArgTy = QualType::getFromOpaquePtr(explicit_type.m_Type);
2054 if (explicit_type.m_IntegralValue) {
2055 // We have a non-TyRef template parameter. Create an integral value from
2056 // the string representation.
2057 auto Res = llvm::APSInt(explicit_type.m_IntegralValue);
2058 Res = Res.extOrTrunc(C.getIntWidth(ArgTy));
2059 TemplateArgs.push_back(TemplateArgument(C, Res, ArgTy));
2060 } else {
2061 TemplateArgs.push_back(ArgTy);
2062 }
2063 }
2064
2065 TemplateArgumentListInfo ExplicitTemplateArgs{};
2066 for (auto TA : TemplateArgs)
2067 ExplicitTemplateArgs.addArgument(
2068 S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));
2069
2070 // ensure valid point of instantiation, SFINAE trap keeps any failure soft
2071 SourceLocation Loc = SourceLocation::getFromRawEncoding(1);
2072 Sema::SFINAETrap Trap(S, /*ForValidityCheck=*/true);
2073
2074 OverloadCandidateSet Overloads(
2075 Loc, OverloadCandidateSet::CandidateSetKind::CSK_Normal);
2076
2077 for (auto i : candidates) {
2078 auto* D = const_cast<Decl*>(unwrap<Decl>(i));
2079 if (auto* FD = dyn_cast<FunctionDecl>(D)) {
2080 S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()),
2081 Args, Overloads);
2082 } else if (auto* FTD = dyn_cast<FunctionTemplateDecl>(D)) {
2083 auto* MD = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl());
2084 if (MD && MD->isExplicitObjectMemberFunction()) {
2085 // The explicit object parameter isn't in Args, so deduce it via the
2086 // method-template path with a synthesized receiver of the record type.
2087 CXXRecordDecl* RD = MD->getParent();
2088 QualType ObjectType = compat::GetTypeFromDecl(RD);
2089 OpaqueValueExpr ObjectExpr(SourceLocation::getFromRawEncoding(1),
2090 ObjectType, ExprValueKind::VK_LValue);
2091 S.AddMethodTemplateCandidate(
2092 FTD, DeclAccessPair::make(FTD, FTD->getAccess()), RD,
2093 &ExplicitTemplateArgs, ObjectType, ObjectExpr.Classify(C), Args,
2094 Overloads);
2095 } else {
2096 // AddTemplateOverloadCandidate is causing a memory leak
2097 // It is a known bug at clang
2098 // call stack: AddTemplateOverloadCandidate -> MakeDeductionFailureInfo
2099 // source:
2100 // https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L731-L756
2101 S.AddTemplateOverloadCandidate(
2102 FTD, DeclAccessPair::make(FTD, FTD->getAccess()),
2103 &ExplicitTemplateArgs, Args, Overloads);
2104 }
2105 }
2106 }
2107
2108 OverloadCandidateSet::iterator Best;
2109 Overloads.BestViableFunction(S, Loc, Best);
2110
2111 FunctionDecl* Result = Best != Overloads.end() ? Best->Function : nullptr;
2112 delete[] Exprs;
2113 return INTEROP_RETURN(Result);
2114}
2115
2116// Gets the AccessSpecifier of the function and checks if it is equal to
2117// the provided AccessSpecifier.
2118bool CheckMethodAccess(ConstFuncRef method, AccessSpecifier AS) {
2119 const auto* D = unwrap<Decl>(method);
2120 if (const auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
2121 return CXXMD->getAccess() == AS;
2122 }
2123
2124 return false;
2125}
2126
2127bool IsMethod(ConstFuncRef method) {
2128 INTEROP_TRACE(method);
2129 const auto* D = unwrap<clang::Decl>(method);
2130 if (const auto* FTD = dyn_cast_or_null<FunctionTemplateDecl>(D))
2131 D = FTD->getTemplatedDecl();
2132 return INTEROP_RETURN(dyn_cast_or_null<CXXMethodDecl>(D));
2133}
2134
2135bool IsPublicMethod(ConstFuncRef method) {
2136 INTEROP_TRACE(method);
2137 return INTEROP_RETURN(CheckMethodAccess(method, AccessSpecifier::AS_public));
2138}
2139
2140bool IsProtectedMethod(ConstFuncRef method) {
2141 INTEROP_TRACE(method);
2142 return INTEROP_RETURN(
2143 CheckMethodAccess(method, AccessSpecifier::AS_protected));
2144}
2145
2146bool IsPrivateMethod(ConstFuncRef method) {
2147 INTEROP_TRACE(method);
2148 return INTEROP_RETURN(CheckMethodAccess(method, AccessSpecifier::AS_private));
2149}
2150
2151bool IsConstructor(ConstFuncRef method) {
2152 INTEROP_TRACE(method);
2153 const auto* D = unwrap<Decl>(method);
2154 if (const auto* FTD = dyn_cast<FunctionTemplateDecl>(D))
2155 return INTEROP_RETURN(IsConstructor(FTD->getTemplatedDecl()));
2156 return INTEROP_RETURN(llvm::isa_and_nonnull<CXXConstructorDecl>(D));
2157}
2158
2159bool IsDestructor(ConstFuncRef method) {
2160 INTEROP_TRACE(method);
2161 const auto* D = unwrap<Decl>(method);
2162 return INTEROP_RETURN(llvm::isa_and_nonnull<CXXDestructorDecl>(D));
2163}
2164
2165bool IsStaticMethod(ConstFuncRef method) {
2166 INTEROP_TRACE(method);
2167 const auto* D = unwrap<Decl>(method);
2168 if (const auto* FTD = llvm::dyn_cast_or_null<FunctionTemplateDecl>(D))
2169 D = FTD->getTemplatedDecl();
2170
2171 if (const auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
2172 return INTEROP_RETURN(CXXMD->isStatic());
2173 }
2174
2175 return INTEROP_RETURN(false);
2176}
2177
2178bool IsExplicit(ConstFuncRef method) {
2179 INTEROP_TRACE(method);
2180 if (!method)
2181 return INTEROP_RETURN(false);
2182
2183 const auto* D = unwrap<Decl>(method);
2184
2185 if (const auto* FTD = llvm::dyn_cast_or_null<FunctionTemplateDecl>(D))
2186 D = FTD->getTemplatedDecl();
2187
2188 if (const auto* CD = llvm::dyn_cast_or_null<CXXConstructorDecl>(D))
2189 return INTEROP_RETURN(CD->isExplicit());
2190
2191 if (const auto* CD = llvm::dyn_cast_or_null<CXXConversionDecl>(D))
2192 return INTEROP_RETURN(CD->isExplicit());
2193
2194 if (const auto* DGD = llvm::dyn_cast_or_null<CXXDeductionGuideDecl>(D))
2195 return INTEROP_RETURN(DGD->isExplicit());
2196
2197 return INTEROP_RETURN(false);
2198}
2199
2200void* GetFunctionAddress(const char* mangled_name) {
2201 INTEROP_TRACE(mangled_name);
2202 auto& I = getInterp();
2203 auto FDAorErr = compat::getSymbolAddress(I, mangled_name);
2204 if (llvm::Error Err = FDAorErr.takeError())
2205 llvm::consumeError(std::move(Err)); // nullptr if missing
2206 else
2207 return INTEROP_RETURN(llvm::jitTargetAddressToPointer<void*>(*FDAorErr));
2208
2209 return INTEROP_RETURN(nullptr);
2210}
2211
2212static void* GetFunctionAddress(const FunctionDecl* FD) {
2213 const auto get_mangled_name = [](const FunctionDecl* FD) {
2214 auto MangleCtxt = getASTContext().createMangleContext();
2215
2216 if (!MangleCtxt->shouldMangleDeclName(FD)) {
2217 return FD->getNameInfo().getName().getAsString();
2218 }
2219
2220 std::string mangled_name;
2221 llvm::raw_string_ostream ostream(mangled_name);
2222
2223 MangleCtxt->mangleName(FD, ostream);
2224
2225 ostream.flush();
2226 delete MangleCtxt;
2227
2228 return mangled_name;
2229 };
2230
2231 // Constructor and Destructors needs to be handled differently
2232 if (!llvm::isa<CXXConstructorDecl>(FD) && !llvm::isa<CXXDestructorDecl>(FD))
2233 return GetFunctionAddress(get_mangled_name(FD).c_str());
2234
2235 return 0;
2236}
2237
2238void* GetFunctionAddress(FuncRef method) {
2239 INTEROP_TRACE(method);
2240 auto* D = unwrap<Decl>(method);
2241 if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
2242 if ((IsTemplateInstantiationOrSpecialization(FD) ||
2243 FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) &&
2244 !FD->getDefinition())
2246 ASTContext& C = getASTContext();
2247 if (isDiscardableGVALinkage(C.GetGVALinkageForFunction(FD)))
2248 ForceCodeGen(FD, getInterp());
2250 }
2251 return INTEROP_RETURN(nullptr);
2252}
2253
2254bool IsVirtualMethod(ConstFuncRef method) {
2255 INTEROP_TRACE(method);
2256 const auto* D = unwrap<Decl>(method);
2257 if (const auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
2258 return INTEROP_RETURN(CXXMD->isVirtual());
2259 }
2260
2261 return INTEROP_RETURN(false);
2262}
2263
2264// Vtable slot index of a virtual method in the target ABI's layout, or -1
2265// if the method is not virtual. Clang's VTableContext yields the right index
2266// for both Itanium (first user virtual after the destructor pair) and
2267// Microsoft (single deleting-dtor slot).
2268static int virtualMethodSlot(ConstFuncRef method) {
2269 const auto* MD = llvm::dyn_cast_or_null<CXXMethodDecl>(unwrap<Decl>(method));
2270 if (!MD || !MD->isVirtual())
2271 return -1;
2272
2273 ASTContext& C = getASTContext();
2274 if (C.getTargetInfo().getCXXABI().isMicrosoft()) {
2275 auto* VTC = llvm::cast<MicrosoftVTableContext>(C.getVTableContext());
2276 return (int)VTC->getMethodVFTableLocation(GlobalDecl(MD)).Index;
2277 }
2278 auto* VTC = llvm::cast<ItaniumVTableContext>(C.getVTableContext());
2279 return (int)VTC->getMethodVTableIndex(GlobalDecl(MD));
2280}
2281
2282// Number of vtable slots from the address point onward for a polymorphic
2283// class (the count applyVTableOverlay copies): destructor slots plus every
2284// virtual. -1 if DRef is not a polymorphic class.
2285static int vtableMethodSlotCount(ConstDeclRef DRef) {
2286 const auto* RD = llvm::dyn_cast_or_null<CXXRecordDecl>(unwrap<Decl>(DRef));
2287 if (RD)
2288 RD = RD->getDefinition();
2289 if (!RD || !RD->isPolymorphic())
2290 return -1;
2291
2292 ASTContext& C = getASTContext();
2293 if (C.getTargetInfo().getCXXABI().isMicrosoft()) {
2294 auto* VTC = llvm::cast<MicrosoftVTableContext>(C.getVTableContext());
2295 const VTableLayout& L = VTC->getVFTableLayout(RD, CharUnits::Zero());
2296 return (int)L.vtable_components().size();
2297 }
2298 auto* VTC = llvm::cast<ItaniumVTableContext>(C.getVTableContext());
2299 const VTableLayout& L = VTC->getVTableLayout(RD);
2300 unsigned AddrPoint = L.getAddressPointIndices()[0];
2301 return (int)(L.vtable_components().size() - AddrPoint);
2302}
2303
2304// True if \c RD's vtable layout is beyond the single-vptr overlay model:
2305// * multiple polymorphic direct bases -> secondary-base subobjects have
2306// their own vptrs that the overlay does not touch, so dispatch through
2307// a pointer to such a subobject would silently hit the original method;
2308// * any virtual base -> the primary vtable has vbase-offset entries
2309// before the address point, and the virtual-base subobject carries a
2310// vtable-in-derived with virtual thunks that the overlay does not
2311// retarget. Returns true so MakeVTableOverlay can refuse instead of
2312// quietly mis-overlaying.
2313static bool hasComplexVTableLayout(const CXXRecordDecl* RD) {
2314 if (RD->getNumVBases() > 0)
2315 return true;
2316 unsigned polymorphic_direct_bases = 0;
2317 for (const auto& B : RD->bases()) {
2318 const auto* BD = B.getType()->getAsCXXRecordDecl();
2319 if (!BD)
2320 continue;
2321 BD = BD->getDefinition();
2322 if (BD && BD->isPolymorphic() && ++polymorphic_direct_bases > 1)
2323 return true;
2324 }
2325 return false;
2326}
2327
2328// ABI-only prefix size (excludes the hidden self-pointer slot CppInterOp
2329// interposes for dtor-hook routing). Itanium has 2 slots (offset-to-top,
2330// type_info); MSVC has 1 (complete-object-locator).
2331#ifdef _WIN32
2332constexpr int kABIPrefixSize = 1;
2333#else
2334constexpr int kABIPrefixSize = 2;
2335#endif
2337 "public prefix size must equal ABI prefix + 1 hidden slot");
2338
2339// Vtable slots hold member functions: on 32-bit MSVC that means __thiscall,
2340// which a free function cannot be declared as (C3865). Use a member of a
2341// base-less class instead; `this` is the object being destroyed. MSVC's
2342// deleting dtor takes (this, int flags), Itanium's D0 only `this`.
2344#ifdef _WIN32
2345 void Wrapper(int flags);
2346#else
2347 void Wrapper();
2348#endif
2349};
2350#ifdef _WIN32
2351using VTableOverlayDtorSlotFn = void (VTableOverlayDtorHost::*)(int);
2352#else
2354#endif
2355
2356// A non-virtual mfp of a base-less class keeps the entry point in its first
2357// pointer-sized word on every ABI we target (MSVC: just the address;
2358// Itanium: {fnptr, adj} with adj = 0).
2360 static_assert(sizeof(VTableOverlayDtorSlotFn) >= sizeof(void*));
2362 std::memcpy(&fn, static_cast<void*>(&slot), sizeof(slot));
2363 return fn;
2364}
2366 void* slot;
2367 std::memcpy(static_cast<void*>(&slot), &fn, sizeof(slot));
2368 return slot;
2369}
2370
2371// Single locus for vptr reads/writes and slot arithmetic in this file;
2372// the public header's VTableOverlayExtraSlot covers the symmetric pun
2373// thunks need on the read side. The owned block layout is:
2374//
2375// [ user extras (N) ] [ hidden self-ptr ] [ ABI prefix ] [ methods ]
2376// ^ ^
2377// address_point - kVTableOverlayPrefixSize
2378// address_point
2379//
2380// The wrapper at the deleting-dtor slot recovers its VTableOverlay from
2381// the hidden self-ptr slot via a fixed-offset load from `this`'s vptr.
2383 void** block; // owned, freed in ~VTableOverlay
2384 void** original_vptr; // restored on caller-driven teardown
2385 void* inst; // object whose vptr was replaced
2387 bool dtor_fired = false; // wrapper started -- skip vptr restore
2388 // Dtor-hook fields. orig_dtor stays null when the caller passed
2389 // on_destroy = nullptr; the wrapper is then not installed at all.
2391 VTableOverlayDtorHook cleanup = nullptr;
2392 void* cleanup_data = nullptr;
2393
2394 VTableOverlay(void** block, void** orig_vptr, void* inst,
2395 std::size_t n_extra)
2396 : block(block), original_vptr(orig_vptr), inst(inst),
2397 n_extra_prefix_slots(n_extra) {
2398 // Stash self-pointer in the hidden slot before publishing the vptr;
2399 // the wrapper reads it at fire time via a fixed offset from vptr.
2400 *hidden_slot() = this;
2402 }
2404 if (!dtor_fired)
2406 delete[] block;
2407 }
2410
2415 return reinterpret_cast<VTableOverlay**>(block + n_extra_prefix_slots);
2416 }
2417
2418 // reinterpret_cast between function and void* is only conditionally
2419 // supported per [expr.reinterpret.cast]/6; memcpy is the well-defined
2420 // alternative on every platform CppInterOp targets.
2421 template <class To, class From> static To BitCastFn(From f) noexcept {
2422 static_assert(sizeof(To) == sizeof(From));
2423 To to;
2424 std::memcpy(&to, &f, sizeof(to));
2425 return to;
2426 }
2427
2428 static void** ReadVPtr(void* inst) {
2429 return *reinterpret_cast<void***>(inst);
2430 }
2431 static void WriteVPtr(void* inst, void** new_vptr) {
2432 *reinterpret_cast<void***>(inst) = new_vptr;
2433 }
2434};
2435
2436// Wrapper installed in the deleting-dtor slot when MakeVTableOverlay was
2437// called with a non-null on_destroy. Recovers the owning VTableOverlay
2438// from `this`'s vptr (hidden-slot fixed-offset load) and runs the
2439// callback BEFORE the original destructor: the object is alive at that
2440// point so the callback can inspect it, and after the original
2441// deleting-destructor returns memory has been freed.
2442#ifdef _WIN32
2443void VTableOverlayDtorHost::Wrapper(int flags) {
2444#else
2446#endif
2447 void** vptr = VTableOverlay::ReadVPtr(this);
2448 VTableOverlay* ov = *reinterpret_cast<VTableOverlay**>(
2450 // Snapshot orig_dtor before user code runs: a misbehaving callback
2451 // that destroys the overlay must not strand the C++ destructor.
2452 auto orig_dtor = ov->orig_dtor;
2453 ov->dtor_fired = true;
2454 if (ov->cleanup)
2455 ov->cleanup(this, ov->cleanup_data);
2456#ifdef _WIN32
2457 (this->*orig_dtor)(flags);
2458#else
2459 (this->*orig_dtor)();
2460#endif
2461}
2462
2463// Minimum slot count a polymorphic class can have from its address point:
2464// Itanium emits the destructor pair (D1 + D0) so the count is at least 2;
2465// Microsoft emits a single deleting-dtor slot so the count is at least 1.
2466// vtableMethodSlotCount returns -1 for non-polymorphic scopes.
2467#ifdef _WIN32
2468constexpr int kMinVTableMethodSlots = 1;
2469#else
2470constexpr int kMinVTableMethodSlots = 2;
2471#endif
2472
2473// Reflection-free pointer surgery: copy inst's vtable, overwrite slots with
2474// fns, install the copy and return a DRef owning it. The slot indices and
2475// count are resolved from reflection by the caller (MakeVTableOverlay).
2476// n_extra_prefix_slots prepends nullptr-initialized void* slots before the
2477// ABI prefix; the caller stashes per-instance data there and thunks read it
2478// via vptr[-(kPrefix + 1 + i)].
2479static VTableOverlay* applyVTableOverlay(void* inst, int total_method_slots,
2480 const int* slots, void* const* fns,
2481 std::size_t n,
2482 std::size_t n_extra_prefix_slots) {
2483 if (!inst || total_method_slots < kMinVTableMethodSlots)
2484 return nullptr;
2485 for (std::size_t i = 0; i < n; ++i) {
2486 if (slots[i] < 0 || slots[i] >= total_method_slots)
2487 return nullptr;
2488 }
2489
2490 // Total block size = N user extras + 1 hidden self-ptr + ABI prefix
2491 // + total_method_slots. The published vtable's address point is at
2492 // block + n_extra_prefix_slots + detail::kVTableOverlayPrefixSize.
2493 constexpr int kPrefix = detail::kVTableOverlayPrefixSize;
2494 const std::size_t total = n_extra_prefix_slots + kPrefix + total_method_slots;
2495
2496 void** orig_vptr = VTableOverlay::ReadVPtr(inst);
2497 // Zero-init so user-extra slots are nullptr (callers will populate).
2498 // The hidden slot at block[n_extra_prefix_slots] is filled by the
2499 // VTableOverlay ctor below. The memcpy then copies the original ABI
2500 // prefix + methods into the remaining region.
2501 void** block = new void*[total]();
2502 std::memcpy(block + n_extra_prefix_slots + 1, orig_vptr - kABIPrefixSize,
2503 (kABIPrefixSize + total_method_slots) * sizeof(void*));
2504
2505 for (std::size_t i = 0; i < n; ++i)
2506 block[n_extra_prefix_slots + kPrefix + slots[i]] = fns[i];
2507
2508 // Per-instance install: the new vptr is written into *this* object only.
2509 // Other live and future instances of the same TyRef continue to use the
2510 // class's original vtable; ~VTableOverlay restores `inst`'s vptr.
2511 return new VTableOverlay(block, orig_vptr, inst, n_extra_prefix_slots);
2512}
2513
2514// Itanium emits the destructor pair (D1, D0) at slots 0 and 1; the
2515// deleting-dtor (D0) at slot 1 is the path operator-delete takes for
2516// heap-allocated objects -- the relevant hook for cppyy / binding proxies
2517// whose Python wrapper drop triggers `delete cppobj`. MSVC emits a single
2518// deleting dtor at slot 0.
2519#ifdef _WIN32
2520constexpr int kDeletingDtorSlot = 0;
2521#else
2522constexpr int kDeletingDtorSlot = 1;
2523#endif
2524
2526MakeVTableOverlay(void* inst, ConstDeclRef base, const ConstFuncRef* methods,
2527 void* const* overlay_fns, std::size_t n_overlays,
2528 std::size_t n_extra_prefix_slots,
2529 VTableOverlayDtorHook on_destroy, void* cleanup_data) {
2530 INTEROP_TRACE(inst, base, methods, overlay_fns, n_overlays,
2531 n_extra_prefix_slots, on_destroy, cleanup_data);
2532 // Refuse layouts the single-primary-vptr overlay cannot fully express,
2533 // so the caller cannot silently produce mis-dispatching objects. Must run
2534 // before vtableMethodSlotCount: on MSVC, getVFTableLayout(RD, offset 0)
2535 // asserts when a virtual-inheritance class has no VFTable at that offset.
2536 if (!inst)
2537 return INTEROP_RETURN(nullptr);
2538 const auto* RD = llvm::dyn_cast_or_null<CXXRecordDecl>(unwrap<Decl>(base));
2539 if (RD)
2540 RD = RD->getDefinition();
2541 if (!RD || !RD->isPolymorphic() || hasComplexVTableLayout(RD))
2542 return INTEROP_RETURN(nullptr);
2543
2544 int total_method_slots = vtableMethodSlotCount(base);
2545 if (total_method_slots < kMinVTableMethodSlots)
2546 return INTEROP_RETURN(nullptr);
2547
2548 llvm::SmallVector<int, 8> slots;
2549 slots.reserve(n_overlays);
2550 for (std::size_t i = 0; i < n_overlays; ++i) {
2551 int slot = virtualMethodSlot(methods[i]);
2552 if (slot < 0)
2553 return INTEROP_RETURN(nullptr);
2554 slots.push_back(slot);
2555 }
2556 auto* ov = applyVTableOverlay(inst, total_method_slots, slots.data(),
2557 overlay_fns, n_overlays,
2558 n_extra_prefix_slots);
2559 if (!ov)
2560 return INTEROP_RETURN(nullptr);
2561
2562 // Optional dtor hook: capture the original D0 (already copied into
2563 // the block), wire the hook fields on the overlay, then publish the
2564 // wrapper at the deleting-dtor slot. Ordering matters -- the fields
2565 // must be set before the wrapper is reachable, otherwise a concurrent
2566 // destruction could fire the wrapper with stale state.
2567 if (on_destroy) {
2568 void** vptr = ov->address_point();
2569 ov->orig_dtor = SlotToDtorFn(vptr[kDeletingDtorSlot]);
2570 ov->cleanup = on_destroy;
2571 ov->cleanup_data = cleanup_data;
2573 }
2574
2575 return INTEROP_RETURN(ov);
2576}
2577
2579 INTEROP_TRACE(overlay);
2580 delete overlay; // ~VTableOverlay restores vptr if dtor hasn't fired.
2581 return INTEROP_VOID_RETURN();
2582}
2583
2584void GetDatamembers(DeclRef DRef, std::vector<DeclRef>& datamembers) {
2585 INTEROP_TRACE(DRef, INTEROP_OUT(datamembers));
2586 auto* D = unwrap<Decl>(DRef);
2587
2588 if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
2589 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
2590 if (CXXRD->hasDefinition())
2591 CXXRD = CXXRD->getDefinition();
2592
2593 llvm::SmallVector<RecordDecl::decl_iterator, 2> stack_begin;
2594 llvm::SmallVector<RecordDecl::decl_iterator, 2> stack_end;
2595 stack_begin.push_back(CXXRD->decls_begin());
2596 stack_end.push_back(CXXRD->decls_end());
2597 while (!stack_begin.empty()) {
2598 if (stack_begin.back() == stack_end.back()) {
2599 stack_begin.pop_back();
2600 stack_end.pop_back();
2601 continue;
2602 }
2603 Decl* D = *(stack_begin.back());
2604 if (auto* FD = llvm::dyn_cast<FieldDecl>(D)) {
2605 if (FD->isAnonymousStructOrUnion()) {
2606 if (const auto* RT = FD->getType()->getAs<RecordType>()) {
2607 if (auto* CXXRD = llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {
2608 stack_begin.back()++;
2609 stack_begin.push_back(CXXRD->decls_begin());
2610 stack_end.push_back(CXXRD->decls_end());
2611 continue;
2612 }
2613 }
2614 }
2615 datamembers.push_back(D);
2616
2617 } else if (auto* USD = llvm::dyn_cast<UsingShadowDecl>(D)) {
2618 if (llvm::isa<FieldDecl>(USD->getTargetDecl()))
2619 datamembers.push_back(USD);
2620 }
2621 stack_begin.back()++;
2622 }
2623 }
2624 return INTEROP_VOID_RETURN();
2625}
2626
2627void GetStaticDatamembers(ConstDeclRef DRef,
2628 std::vector<DeclRef>& datamembers) {
2629 INTEROP_TRACE(DRef, INTEROP_OUT(datamembers));
2630 GetClassDecls<VarDecl>(DRef, datamembers);
2631 return INTEROP_VOID_RETURN();
2632}
2633
2634void GetEnumConstantDatamembers(ConstDeclRef DRef,
2635 std::vector<DeclRef>& datamembers,
2636 bool include_enum_class) {
2637 INTEROP_TRACE(DRef, INTEROP_OUT(datamembers), include_enum_class);
2638 std::vector<DeclRef> EDs;
2639 GetClassDecls<EnumDecl>(DRef, EDs);
2640 for (DeclRef i : EDs) {
2641 auto* ED = unwrap<EnumDecl>(i);
2642
2643 bool is_class_tagged = ED->isScopedUsingClassTag();
2644 if (is_class_tagged && !include_enum_class)
2645 continue;
2646
2647 std::copy(ED->enumerator_begin(), ED->enumerator_end(),
2648 std::back_inserter(datamembers));
2649 }
2650 return INTEROP_VOID_RETURN();
2651}
2652
2653DeclRef LookupDatamember(const std::string& name, ConstDeclRef parent) {
2654 INTEROP_TRACE(name, parent);
2655 const clang::DeclContext* Within = nullptr;
2656 if (parent) {
2657 const auto* D = unwrap<clang::Decl>(parent);
2658 Within = llvm::dyn_cast<clang::DeclContext>(D);
2659 }
2660
2661 auto* ND = CppInternal::utils::Lookup::Named(&getSema(), name, Within);
2662 if (ND && ND != (clang::NamedDecl*)-1) {
2663 if (llvm::isa_and_nonnull<clang::FieldDecl>(ND)) {
2664 return INTEROP_RETURN(ND);
2665 }
2666 }
2667
2668 return INTEROP_RETURN(nullptr);
2669}
2670
2671bool IsLambdaClass(ConstTypeRef TyRef) {
2672 INTEROP_TRACE(TyRef);
2673 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2674 if (auto* CXXRD = QT->getAsCXXRecordDecl()) {
2675 return INTEROP_RETURN(CXXRD->isLambda());
2676 }
2677 return INTEROP_RETURN(false);
2678}
2679
2680TypeRef GetVariableType(ConstDeclRef var) {
2681 INTEROP_TRACE(var);
2682 const auto* D = unwrap<Decl>(var);
2683
2684 if (const auto* DD = llvm::dyn_cast_or_null<DeclaratorDecl>(D)) {
2685 QualType QT = DD->getType();
2686
2687 // Check if the TyRef is a typedef TyRef
2688 if (QT->isTypedefNameType()) {
2689 return INTEROP_RETURN(QT.getAsOpaquePtr());
2690 }
2691
2692 // Else, return the canonical TyRef
2693 QT = QT.getCanonicalType();
2694 return INTEROP_RETURN(QT.getAsOpaquePtr());
2695 }
2696
2697 if (const auto* ECD = llvm::dyn_cast_or_null<EnumConstantDecl>(D))
2698 return INTEROP_RETURN(ECD->getType().getAsOpaquePtr());
2699
2700 return INTEROP_RETURN(nullptr);
2701}
2702
2704 CXXRecordDecl* BaseCXXRD) {
2705 if (!D)
2706 return 0;
2707
2708 auto& C = I.getSema().getASTContext();
2709
2710 if (auto* FD = llvm::dyn_cast<FieldDecl>(D)) {
2711 clang::RecordDecl* FieldParentRecordDecl = FD->getParent();
2712 intptr_t offset = C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity();
2713 while (FieldParentRecordDecl->isAnonymousStructOrUnion()) {
2714 clang::RecordDecl* anon = FieldParentRecordDecl;
2715 FieldParentRecordDecl = llvm::dyn_cast<RecordDecl>(anon->getParent());
2716 for (auto F = FieldParentRecordDecl->field_begin();
2717 F != FieldParentRecordDecl->field_end(); ++F) {
2718 const auto* RT = F->getType()->getAs<RecordType>();
2719 if (!RT)
2720 continue;
2721 if (anon == RT->getDecl()) {
2722 FD = *F;
2723 break;
2724 }
2725 }
2726 offset += C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity();
2727 }
2728 if (BaseCXXRD && BaseCXXRD != FieldParentRecordDecl->getCanonicalDecl()) {
2729 // FieldDecl FD belongs to some class C, but the base class BaseCXXRD is
2730 // not C. That means BaseCXXRD derives from C. Offset needs to be
2731 // calculated for Derived class
2732
2733 // Depth first Search is performed to the class that declares FD from
2734 // the base class
2735 std::vector<CXXRecordDecl*> stack;
2736 std::map<CXXRecordDecl*, CXXRecordDecl*> direction;
2737 stack.push_back(BaseCXXRD);
2738 while (!stack.empty()) {
2739 CXXRecordDecl* RD = stack.back();
2740 stack.pop_back();
2741 size_t num_bases = GetNumBases(RD);
2742 bool flag = false;
2743 for (size_t i = 0; i < num_bases; i++) {
2744 auto* CRD = unwrap<CXXRecordDecl>(GetBaseClass(RD, i));
2745 direction[CRD] = RD;
2746 if (CRD == FieldParentRecordDecl) {
2747 flag = true;
2748 break;
2749 }
2750 stack.push_back(CRD);
2751 }
2752 if (flag)
2753 break;
2754 }
2755 if (auto* RD = llvm::dyn_cast<CXXRecordDecl>(FieldParentRecordDecl)) {
2756 // add in the offsets for the (multi level) base classes
2757 RD = RD->getCanonicalDecl();
2758 while (BaseCXXRD != RD) {
2759 CXXRecordDecl* Parent = direction.at(RD);
2760 offset +=
2761 C.getASTRecordLayout(Parent).getBaseClassOffset(RD).getQuantity();
2762 RD = Parent;
2763 }
2764 } else {
2765 assert(false && "Unreachable");
2766 }
2767 }
2768 return offset;
2769 }
2770
2771 if (auto* VD = llvm::dyn_cast<VarDecl>(D)) {
2772 auto GD = GlobalDecl(VD);
2773 std::string mangledName;
2774 compat::maybeMangleDeclName(GD, mangledName);
2775 void* address = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
2776 mangledName.c_str());
2777
2778 if (!address)
2779 address = I.getAddressOfGlobal(GD);
2780 if (!address) {
2781 if (!VD->hasInit()) {
2782 // The initializer feeding the constexpr fast path below may live on
2783 // an already-parsed out-of-line definition (a non-template class's
2784 // static data member, e.g. std::partial_ordering::less): prefer it,
2785 // with no Sema work at all. Only a variable instantiated from a
2786 // template can need Sema::InstantiateVariableDefinition — and
2787 // without an instantiation pattern that call dereferences a null
2788 // VarDecl in release builds.
2789 if (VarDecl* Def = VD->getDefinition()) {
2790 VD = Def;
2791 } else if (VD->getTemplateInstantiationPattern()) {
2793 getSema().InstantiateVariableDefinition(SourceLocation(), VD);
2794 if (VarDecl* Inst = VD->getDefinition())
2795 VD = Inst;
2796 }
2797 }
2798 if (VD->hasInit() &&
2799 (VD->isConstexpr() || VD->getType().isConstQualified())) {
2800 if (const APValue* val = VD->evaluateValue()) {
2801 if (VD->getType()->isIntegralType(C)) {
2802 return (intptr_t)val->getInt().getRawData();
2803 }
2804 }
2805 }
2806 }
2807 if (!address) {
2808 auto Linkage = C.GetGVALinkageForVariable(VD);
2809 if (isDiscardableGVALinkage(Linkage))
2810 ForceCodeGen(VD, I);
2811 }
2812 auto VDAorErr = compat::getSymbolAddress(I, StringRef(mangledName));
2813 if (!VDAorErr) {
2814 llvm::logAllUnhandledErrors(VDAorErr.takeError(), llvm::errs(),
2815 "Failed to GetVariableOffset:");
2816 return 0;
2817 }
2818 return (intptr_t)jitTargetAddressToPointer<void*>(VDAorErr.get());
2819 }
2820
2821 return 0;
2822}
2823
2824intptr_t GetVariableOffset(ConstDeclRef var, ConstDeclRef parent) {
2825 INTEROP_TRACE(var, parent);
2826 // The internal overload may trigger JIT materialization — logically const.
2827 auto* D = const_cast<Decl*>(unwrap<Decl>(var));
2828 auto* RD = const_cast<CXXRecordDecl*>(
2829 llvm::dyn_cast_or_null<CXXRecordDecl>(unwrap<Decl>(parent)));
2830 return INTEROP_RETURN(GetVariableOffset(getInterp(), D, RD));
2831}
2832
2833// Check if the Access Specifier of the variable matches the provided value.
2834bool CheckVariableAccess(ConstDeclRef var, AccessSpecifier AS) {
2835 const auto* D = unwrap<Decl>(var);
2836 return D->getAccess() == AS;
2837}
2838
2839bool IsPublicVariable(ConstDeclRef var) {
2840 INTEROP_TRACE(var);
2841 return INTEROP_RETURN(CheckVariableAccess(var, AccessSpecifier::AS_public));
2842}
2843
2844bool IsProtectedVariable(ConstDeclRef var) {
2845 INTEROP_TRACE(var);
2846 return INTEROP_RETURN(
2847 CheckVariableAccess(var, AccessSpecifier::AS_protected));
2848}
2849
2850bool IsPrivateVariable(ConstDeclRef var) {
2851 INTEROP_TRACE(var);
2852 return INTEROP_RETURN(CheckVariableAccess(var, AccessSpecifier::AS_private));
2853}
2854
2855bool IsStaticVariable(ConstDeclRef var) {
2856 INTEROP_TRACE(var);
2857 const auto* D = unwrap<Decl>(var);
2858 if (llvm::isa_and_nonnull<VarDecl>(D)) {
2859 return INTEROP_RETURN(true);
2860 }
2861
2862 return INTEROP_RETURN(false);
2863}
2864
2865bool IsConstVariable(ConstDeclRef var) {
2866 INTEROP_TRACE(var);
2867 const auto* D = unwrap<clang::Decl>(var);
2868
2869 if (const auto* VD = llvm::dyn_cast_or_null<ValueDecl>(D)) {
2870 return INTEROP_RETURN(VD->getType().isConstQualified());
2871 }
2872
2873 return INTEROP_RETURN(false);
2874}
2875
2876bool IsRecordType(ConstTypeRef TyRef) {
2877 INTEROP_TRACE(TyRef);
2878 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2879 return INTEROP_RETURN(QT->isRecordType());
2880}
2881
2882bool IsPODType(ConstTypeRef TyRef) {
2883 INTEROP_TRACE(TyRef);
2884 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2885
2886 if (QT.isNull())
2887 return INTEROP_RETURN(false);
2888
2889 return INTEROP_RETURN(QT.isPODType(getASTContext()));
2890}
2891
2892bool IsIntegerType(ConstTypeRef TyRef, Signedness* s) {
2893 INTEROP_TRACE(TyRef, s);
2894 if (!TyRef)
2895 return INTEROP_RETURN(false);
2896 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2897 if (!QT->hasIntegerRepresentation())
2898 return INTEROP_RETURN(false);
2899 if (s) {
2900 *s = QT->hasSignedIntegerRepresentation() ? Signedness::kSigned
2901 : Signedness::kUnsigned;
2902 }
2903 return INTEROP_RETURN(true);
2904}
2905
2906bool IsFloatingType(ConstTypeRef TyRef) {
2907 INTEROP_TRACE(TyRef);
2908 if (!TyRef)
2909 return INTEROP_RETURN(false);
2910 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2911 return INTEROP_RETURN(QT->hasFloatingRepresentation());
2912}
2913
2914bool IsSameType(ConstTypeRef type_a, ConstTypeRef type_b) {
2915 INTEROP_TRACE(type_a, type_b);
2916 if (!type_a || !type_b)
2917 return INTEROP_RETURN(false);
2918 QualType QT1 = QualType::getFromOpaquePtr(type_a.data);
2919 QualType QT2 = QualType::getFromOpaquePtr(type_b.data);
2920 return INTEROP_RETURN(getASTContext().hasSameType(QT1, QT2));
2921}
2922
2923bool IsPointerType(ConstTypeRef TyRef) {
2924 INTEROP_TRACE(TyRef);
2925 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2926 return INTEROP_RETURN(QT->isPointerType());
2927}
2928
2929bool IsVoidPointerType(ConstTypeRef TyRef) {
2930 INTEROP_TRACE(TyRef);
2931 if (!TyRef)
2932 return INTEROP_RETURN(false);
2933 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2934 return INTEROP_RETURN(QT->isVoidPointerType());
2935}
2936
2937TypeRef GetPointeeType(ConstTypeRef TyRef) {
2938 INTEROP_TRACE(TyRef);
2939 if (!IsPointerType(TyRef))
2940 return INTEROP_RETURN(nullptr);
2941 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2942 return INTEROP_RETURN(QT->getPointeeType().getAsOpaquePtr());
2943}
2944
2945bool IsReferenceType(ConstTypeRef TyRef) {
2946 INTEROP_TRACE(TyRef);
2947 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2948 return INTEROP_RETURN(QT->isReferenceType());
2949}
2950
2951ValueKind GetValueKind(ConstTypeRef TyRef) {
2952 INTEROP_TRACE(TyRef);
2953 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2954 if (QT->isRValueReferenceType())
2955 return INTEROP_RETURN(ValueKind::RValue);
2956 if (QT->isLValueReferenceType())
2957 return INTEROP_RETURN(ValueKind::LValue);
2958 return INTEROP_RETURN(ValueKind::None);
2959}
2960
2961TypeRef GetPointerType(ConstTypeRef TyRef) {
2962 INTEROP_TRACE(TyRef);
2963 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2964 return INTEROP_RETURN(getASTContext().getPointerType(QT).getAsOpaquePtr());
2965}
2966
2967TypeRef GetReferencedType(ConstTypeRef TyRef, bool rvalue) {
2968 INTEROP_TRACE(TyRef, rvalue);
2969 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2970 if (rvalue)
2971 return INTEROP_RETURN(
2972 getASTContext().getRValueReferenceType(QT).getAsOpaquePtr());
2973 return INTEROP_RETURN(
2974 getASTContext().getLValueReferenceType(QT).getAsOpaquePtr());
2975}
2976
2977TypeRef GetNonReferenceType(ConstTypeRef TyRef) {
2978 INTEROP_TRACE(TyRef);
2979 if (!IsReferenceType(TyRef))
2980 return INTEROP_RETURN(nullptr);
2981 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2982 return INTEROP_RETURN(QT.getNonReferenceType().getAsOpaquePtr());
2983}
2984
2985TypeRef GetUnderlyingType(ConstTypeRef TyRef) {
2986 INTEROP_TRACE(TyRef);
2987 if (!TyRef)
2988 return INTEROP_RETURN(nullptr);
2989 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2990 QT = QT->getCanonicalTypeUnqualified();
2991
2992 // Recursively remove array dimensions
2993 while (QT->isArrayType())
2994 QT = QualType(QT->getArrayElementTypeNoTypeQual(), 0);
2995
2996 // Recursively reduce pointer depth till we are left with a pointerless
2997 // TyRef.
2998 for (auto PT = QT->getPointeeType(); !PT.isNull();
2999 PT = QT->getPointeeType()) {
3000 QT = PT;
3001 }
3002 QT = QT->getCanonicalTypeUnqualified();
3003 return INTEROP_RETURN(QT.getAsOpaquePtr());
3004}
3005
3006std::string GetTypeAsString(ConstTypeRef var) {
3007 INTEROP_TRACE(var);
3008 QualType QT = QualType::getFromOpaquePtr(var.data);
3009 PrintingPolicy Policy(getASTContext().getPrintingPolicy());
3010 Policy.Bool = true; // Print bool instead of _Bool.
3011 Policy.SuppressTagKeyword = true; // Do not print `class std::string`.
3012 Policy.Suppress_Elab = true;
3013 Policy.FullyQualifiedName = true;
3014 return INTEROP_RETURN(QT.getAsString(Policy));
3015}
3016
3017TypeRef GetCanonicalType(ConstTypeRef TyRef) {
3018 INTEROP_TRACE(TyRef);
3019 if (!TyRef)
3020 return INTEROP_RETURN(nullptr);
3021 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
3022 return INTEROP_RETURN(QT.getCanonicalType().getAsOpaquePtr());
3023}
3024
3025bool HasTypeQualifier(ConstTypeRef TyRef, QualKind qual) {
3026 INTEROP_TRACE(TyRef, qual);
3027 if (!TyRef)
3028 return INTEROP_RETURN(false);
3029
3030 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
3031 if (qual & QualKind::Const) {
3032 if (!QT.isConstQualified())
3033 return INTEROP_RETURN(false);
3034 }
3035 if (qual & QualKind::Volatile) {
3036 if (!QT.isVolatileQualified())
3037 return INTEROP_RETURN(false);
3038 }
3039 if (qual & QualKind::Restrict) {
3040 if (!QT.isRestrictQualified())
3041 return INTEROP_RETURN(false);
3042 }
3043 return INTEROP_RETURN(true);
3044}
3045
3046TypeRef RemoveTypeQualifier(ConstTypeRef TyRef, QualKind qual) {
3047 INTEROP_TRACE(TyRef, qual);
3048 if (!TyRef)
3049 return INTEROP_RETURN(nullptr);
3050
3051 auto QT = QualType(QualType::getFromOpaquePtr(TyRef.data));
3052 if (qual & QualKind::Const)
3053 QT.removeLocalConst();
3054 if (qual & QualKind::Volatile)
3055 QT.removeLocalVolatile();
3056 if (qual & QualKind::Restrict)
3057 QT.removeLocalRestrict();
3058 return INTEROP_RETURN(QT.getAsOpaquePtr());
3059}
3060
3061TypeRef AddTypeQualifier(ConstTypeRef TyRef, QualKind qual) {
3062 INTEROP_TRACE(TyRef, qual);
3063 if (!TyRef)
3064 return INTEROP_RETURN(nullptr);
3065
3066 auto QT = QualType(QualType::getFromOpaquePtr(TyRef.data));
3067 if (qual & QualKind::Const) {
3068 if (!QT.isConstQualified())
3069 QT.addConst();
3070 }
3071 if (qual & QualKind::Volatile) {
3072 if (!QT.isVolatileQualified())
3073 QT.addVolatile();
3074 }
3075 if (qual & QualKind::Restrict) {
3076 if (!QT.isRestrictQualified())
3077 QT.addRestrict();
3078 }
3079 return INTEROP_RETURN(QT.getAsOpaquePtr());
3080}
3081
3082// Registers all permutations of a word set
3083static void RegisterPerms(llvm::StringMap<QualType>& Map, QualType QT,
3084 llvm::SmallVectorImpl<llvm::StringRef>& Words) {
3085 std::sort(Words.begin(), Words.end());
3086 do {
3087 std::string Key;
3088 for (size_t i = 0; i < Words.size(); ++i) {
3089 if (i > 0)
3090 Key += ' ';
3091 Key += Words[i].str();
3092 }
3093 Map[Key] = QT;
3094 } while (std::next_permutation(Words.begin(), Words.end()));
3095}
3096ALLOW_ACCESS(ASTContext, Types, llvm::SmallVector<clang::Type*, 0>);
3097static void PopulateBuiltinMap(ASTContext& Context) {
3098 const PrintingPolicy Policy(Context.getLangOpts());
3099 auto& BuiltinMap = GetInterpreters().back().BuiltinMap;
3100 const auto& Types = ACCESS(Context, Types);
3101
3102 for (clang::Type* T : Types) {
3103 auto* BT = llvm::dyn_cast<BuiltinType>(T);
3104 if (!BT || BT->isPlaceholderType())
3105 continue;
3106
3107 QualType QT(BT, 0);
3108 std::string Name = QT.getAsString(Policy);
3109 if (Name.empty() || Name[0] == '<')
3110 continue;
3111
3112 // Initial entry (e.g., "int", "unsigned long")
3113 BuiltinMap[Name] = QT;
3114
3115 llvm::SmallVector<llvm::StringRef, 4> Words;
3116 llvm::StringRef(Name).split(Words, ' ', -1, false);
3117
3118 bool hasInt = false;
3119 bool hasSigned = false;
3120 bool hasUnsigned = false;
3121 bool hasChar = false;
3122 bool isModifiable = false;
3123
3124 for (auto W : Words) {
3125 if (W == "int")
3126 hasInt = true;
3127 else if (W == "signed")
3128 hasSigned = true;
3129 else if (W == "unsigned")
3130 hasUnsigned = true;
3131 else if (W == "char")
3132 hasChar = true;
3133
3134 if (W == "long" || W == "short" || hasInt)
3135 isModifiable = true;
3136 }
3137
3138 // Skip things like 'float' or 'double' that aren't combined
3139 if (!isModifiable && !hasUnsigned && !hasSigned)
3140 continue;
3141
3142 // Register base permutations (e.g., "long long" or "unsigned int")
3143 if (Words.size() > 1)
3144 RegisterPerms(BuiltinMap, QT, Words);
3145
3146 // Expansion: Add "int" suffix where missing (e.g., "short" -> "short int")
3147 if (!hasInt && !hasChar) {
3148 auto WithInt = Words;
3149 WithInt.push_back("int");
3150 RegisterPerms(BuiltinMap, QT, WithInt);
3151
3152 // If we are adding 'int', we should also try adding 'signed'
3153 // to cover cases like "short" -> "signed short int"
3154 if (!hasSigned && !hasUnsigned) {
3155 auto WithBoth = WithInt;
3156 WithBoth.push_back("signed");
3157 RegisterPerms(BuiltinMap, QT, WithBoth);
3158 }
3159 }
3160
3161 // Expansion: Add "signed" prefix
3162 // (e.g., "int" -> "signed int", "long" -> "signed long")
3163 if (!hasSigned && !hasUnsigned) {
3164 auto WithSigned = Words;
3165 WithSigned.push_back("signed");
3166 RegisterPerms(BuiltinMap, QT, WithSigned);
3167 }
3168 }
3169
3170 // Explicit global synonym
3171 BuiltinMap["signed"] = Context.IntTy;
3172 BuiltinMap["unsigned"] = Context.UnsignedIntTy;
3173}
3174static QualType findBuiltinType(llvm::StringRef typeName, ASTContext& Context) {
3175 llvm::StringMap<QualType>& BuiltinMap = GetInterpreters().back().BuiltinMap;
3176 if (BuiltinMap.empty())
3177 PopulateBuiltinMap(Context);
3178
3179 // Fast Lookup
3180 auto It = BuiltinMap.find(typeName);
3181 if (It != BuiltinMap.end())
3182 return It->second;
3183
3184 return QualType(); // Return null if not a builtin
3185}
3186static std::optional<QualType> GetTypeInternal(const Decl* D) {
3187 if (!D)
3188 return {};
3189 // Even though typedefs derive from TypeDecl, their getTypeForDecl()
3190 // returns a nullptr.
3191 if (const auto* TND = llvm::dyn_cast_or_null<TypedefNameDecl>(D))
3192 return TND->getUnderlyingType();
3193
3194 if (const auto* VD = dyn_cast<ValueDecl>(D))
3195 return VD->getType();
3196
3197 if (const auto* TD = llvm::dyn_cast_or_null<TypeDecl>(D))
3198 return compat::GetTypeFromDecl(TD);
3199
3200 return {};
3201}
3202
3203TypeRef GetType(const std::string& name, ConstDeclRef parent /*= nullptr*/) {
3204 INTEROP_TRACE(name, parent);
3205 QualType builtin = findBuiltinType(name, getASTContext());
3206 if (!builtin.isNull())
3207 return INTEROP_RETURN(builtin.getAsOpaquePtr());
3208
3209 return INTEROP_RETURN(GetTypeFromScope(GetNamed(name, parent)));
3210}
3211
3212TypeRef GetComplexType(ConstTypeRef TyRef) {
3213 INTEROP_TRACE(TyRef);
3214 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
3215
3216 return INTEROP_RETURN(getASTContext().getComplexType(QT).getAsOpaquePtr());
3217}
3218
3219TypeRef GetTypeFromScope(ConstDeclRef DRef) {
3220 INTEROP_TRACE(DRef);
3221 if (!DRef)
3222 return INTEROP_RETURN(nullptr);
3223
3224 if (auto QT = GetTypeInternal(unwrap<Decl>(DRef)))
3225 return INTEROP_RETURN(QT->getAsOpaquePtr());
3226
3227 return INTEROP_RETURN(nullptr);
3228}
3229
3230// Internal functions that are not needed outside the library are
3231// encompassed in an anonymous namespace as follows.
3232namespace {
3233static unsigned long long gWrapperSerial = 0LL;
3234
3235enum EReferenceType { kNotReference, kLValueReference, kRValueReference };
3236
3237// Start of JitCall Helper Functions
3238
3239#define DEBUG_TYPE "jitcall"
3240
3241// FIXME: Use that routine throughout CallFunc's port in places such as
3242// make_narg_call.
3243inline void indent(std::ostringstream& buf, int indent_level) {
3244 static const std::string kIndentString(" ");
3245 for (int i = 0; i < indent_level; ++i)
3246 buf << kIndentString;
3247}
3248
3249void* compile_wrapper(compat::Interpreter& I, const std::string& wrapper_name,
3250 const std::string& wrapper,
3251 bool withAccessControl = true) {
3252 LLVM_DEBUG(dbgs() << "Compiling '" << wrapper_name << "'\n");
3253 return I.compileFunction(wrapper_name, wrapper, false /*ifUnique*/,
3254 withAccessControl);
3255}
3256
3257void get_type_as_string(QualType QT, std::string& type_name, ASTContext& C,
3258 PrintingPolicy Policy) {
3259 // TODO: Implement cling desugaring from utils::AST
3260 // cling::utils::Transform::GetPartiallyDesugaredType()
3261 // Desugar template type alias specializations (e.g. std::enable_if_t,
3262 // std::remove_cvref_t). Their printed form can carry expression-level
3263 // template arguments (variable-template references, SFINAE predicates)
3264 // that PrintingPolicy::FullyQualifiedName does not propagate into, so the
3265 // emitted text may reference identifiers like `is_constructible_v` without
3266 // the `std::` qualifier and fail to compile in the wrapper. Regular
3267 // typedefs (e.g. std::string) keep their sugared name.
3268 while (const auto* TST = QT->getAs<TemplateSpecializationType>()) {
3269 if (!TST->isTypeAlias())
3270 break;
3271 QT = TST->desugar();
3272 }
3273 if (!QT->isTypedefNameType() || QT->isBuiltinType())
3274 QT = QT.getDesugaredType(C);
3275 Policy.Suppress_Elab = true;
3276 Policy.SuppressTagKeyword = !QT->isEnumeralType();
3277 Policy.FullyQualifiedName = true;
3278 Policy.UsePreferredNames = false;
3279 QT.getAsStringInternal(type_name, Policy);
3280}
3281
3282static void GetDeclName(const clang::Decl* D, ASTContext& Context,
3283 std::string& name) {
3284 // Helper to extract a fully qualified name from a Decl
3285 PrintingPolicy Policy(Context.getPrintingPolicy());
3286 Policy.SuppressTagKeyword = true;
3287 Policy.SuppressUnwrittenScope = true;
3288 Policy.Print_Canonical_Types = true;
3289 if (const auto* TD = dyn_cast<TypeDecl>(D)) {
3290 // This is a class, struct, or union member.
3291 QualType QT;
3292 if (const auto* Typedef = dyn_cast<const TypedefDecl>(TD)) {
3293 // Handle the typedefs to anonymous types.
3294 QT = Typedef->getTypeSourceInfo()->getType();
3295 } else
3296 QT = compat::GetTypeFromDecl(TD);
3297 get_type_as_string(QT, name, Context, Policy);
3298 } else if (const auto* ND = dyn_cast<NamedDecl>(D)) {
3299 // This is a namespace member.
3300 raw_string_ostream stream(name);
3301 ND->getNameForDiagnostic(stream, Policy, /*Qualified=*/true);
3302 stream.flush();
3303 }
3304}
3305
3306void collect_type_info(const FunctionDecl* FD, QualType& QT,
3307 std::ostringstream& typedefbuf,
3308 std::ostringstream& callbuf, std::string& type_name,
3309 EReferenceType& refType, bool& isPointer,
3310 int indent_level, bool forArgument) {
3311 //
3312 // Collect information about the TyRef of a function parameter
3313 // needed for building the wrapper function.
3314 //
3315 ASTContext& C = FD->getASTContext();
3316 PrintingPolicy Policy(C.getPrintingPolicy());
3317 Policy.Suppress_Elab = true;
3318 refType = kNotReference;
3319 if (QT->isRecordType()) {
3320 if (forArgument) {
3321 get_type_as_string(QT, type_name, C, Policy);
3322 return;
3323 }
3324 if (auto* CXXRD = QT->getAsCXXRecordDecl()) {
3325 if (CXXRD->isLambda()) {
3326 std::string fn_name;
3327 llvm::raw_string_ostream stream(fn_name);
3328 Policy.FullyQualifiedName = true;
3329 Policy.SuppressUnwrittenScope = true;
3330 FD->getNameForDiagnostic(stream, Policy,
3331 /*Qualified=*/false);
3332 type_name = "__internal_CppInterOp::function<decltype(" + fn_name +
3333 ")>::result_type";
3334 return;
3335 }
3336 }
3337 }
3338 if (QT.getNonReferenceType()->isFunctionPointerType() ||
3339 QT.getNonReferenceType()->isFunctionProtoType()) {
3340 clang::QualType NRQT = QT.getNonReferenceType();
3341 std::string fp_typedef_name;
3342 {
3343 std::ostringstream nm;
3344 nm << "FP" << gWrapperSerial++;
3345 type_name = nm.str();
3346 raw_string_ostream OS(fp_typedef_name);
3347 NRQT.print(OS, Policy, type_name);
3348 OS.flush();
3349 }
3350
3351 indent(typedefbuf, indent_level);
3352
3353 typedefbuf << "typedef " << fp_typedef_name << ";\n";
3354
3355 if (QT->isRValueReferenceType())
3356 refType = kRValueReference;
3357 else
3358 refType = kLValueReference;
3359 return;
3360 } else if (QT->isMemberPointerType()) {
3361 std::string mp_typedef_name;
3362 {
3363 std::ostringstream nm;
3364 nm << "MP" << gWrapperSerial++;
3365 type_name = nm.str();
3366 raw_string_ostream OS(mp_typedef_name);
3367 QT.print(OS, Policy, type_name);
3368 OS.flush();
3369 }
3370
3371 indent(typedefbuf, indent_level);
3372
3373 typedefbuf << "typedef " << mp_typedef_name << ";\n";
3374 return;
3375 } else if (QT->isPointerType()) {
3376 isPointer = true;
3377 QT = cast<clang::PointerType>(QT.getCanonicalType())->getPointeeType();
3378 } else if (QT->isReferenceType()) {
3379 if (QT->isRValueReferenceType())
3380 refType = kRValueReference;
3381 else
3382 refType = kLValueReference;
3383 QT = cast<ReferenceType>(QT.getCanonicalType())->getPointeeType();
3384 }
3385 // Fall through for the array TyRef to deal with reference/pointer ro array
3386 // TyRef.
3387 if (QT->isArrayType()) {
3388 std::string ar_typedef_name;
3389 {
3390 std::ostringstream ar;
3391 ar << "AR" << gWrapperSerial++;
3392 type_name = ar.str();
3393 raw_string_ostream OS(ar_typedef_name);
3394 QT.print(OS, Policy, type_name);
3395 OS.flush();
3396 }
3397 indent(typedefbuf, indent_level);
3398 typedefbuf << "typedef " << ar_typedef_name << ";\n";
3399 return;
3400 }
3401 get_type_as_string(QT, type_name, C, Policy);
3402}
3403
3404void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
3405 std::ostringstream& typedefbuf, std::ostringstream& callbuf,
3406 const std::string& class_name, int indent_level,
3407 bool array = false) {
3408 // Make a code string that follows this pattern:
3409 //
3410 // ClassName(args...)
3411 // OR
3412 // ClassName[nary] // array of objects
3413 //
3414
3415 if (array)
3416 callbuf << class_name << "[nary]";
3417 else
3418 callbuf << class_name;
3419
3420 // We cannot pass initialization parameters if we call array new
3421 if (N && !array) {
3422 callbuf << "(";
3423 for (unsigned i = 0U; i < N; ++i) {
3424 const ParmVarDecl* PVD = FD->getParamDecl(i);
3425 QualType Ty = PVD->getType();
3426 QualType QT = Ty.getCanonicalType();
3427 std::string type_name;
3428 EReferenceType refType = kNotReference;
3429 bool isPointer = false;
3430 collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
3431 isPointer, indent_level, true);
3432 if (i) {
3433 callbuf << ',';
3434 if (i % 2) {
3435 callbuf << ' ';
3436 } else {
3437 callbuf << "\n";
3438 indent(callbuf, indent_level);
3439 }
3440 }
3441 if (refType != kNotReference) {
3442 callbuf << "(" << type_name.c_str()
3443 << (refType == kLValueReference ? "&" : "&&") << ")*("
3444 << type_name.c_str() << "*)args[" << i << "]";
3445 } else if (isPointer) {
3446 callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
3447 } else {
3448 callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
3449 }
3450 }
3451 callbuf << ")";
3452 }
3453 // This can be zero or default-initialized
3454 else if (const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
3455 CD && CD->isDefaultConstructor() && !array) {
3456 callbuf << "()";
3457 }
3458}
3459
3460const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) {
3461 const auto* DC = FD->getDeclContext();
3462 while (DC->isTransparentContext()) {
3463 DC = DC->getParent();
3464 assert(DC && "All transparent contexts should have a parent!");
3465 }
3466 return DC;
3467}
3468
3469void make_narg_call(const FunctionDecl* FD, const std::string& return_type,
3470 const unsigned N, std::ostringstream& typedefbuf,
3471 std::ostringstream& callbuf, const std::string& class_name,
3472 int indent_level) {
3473 //
3474 // Make a code string that follows this pattern:
3475 //
3476 // ((<class>*)obj)-><method>(*(<arg-i-TyRef>*)args[i], ...)
3477 //
3478
3479 // Sometimes it's necessary that we cast the function we want to call
3480 // first to its explicit function TyRef before calling it. This is supposed
3481 // to prevent that we accidentally ending up in a function that is not
3482 // the one we're supposed to call here (e.g. because the C++ function
3483 // lookup decides to take another function that better fits). This method
3484 // has some problems, e.g. when we call a function with default arguments
3485 // and we don't provide all arguments, we would fail with this pattern.
3486 // Same applies with member methods which seem to cause parse failures
3487 // even when we supply the object parameter. Therefore we only use it in
3488 // cases where we know it works and set this variable to true when we do.
3489
3490 // true if not a overloaded operators or the overloaded operator is call
3491 // operator
3492 bool op_flag = !FD->isOverloadedOperator() ||
3493 FD->getOverloadedOperator() == clang::OO_Call;
3494
3495 bool ShouldCastFunction = !isa<CXXMethodDecl>(FD) &&
3496 N == FD->getNumParams() && op_flag &&
3497 !FD->isTemplateInstantiation();
3498 if (ShouldCastFunction) {
3499 callbuf << "(";
3500 callbuf << "(";
3501 callbuf << return_type << " (&)";
3502 {
3503 callbuf << "(";
3504 for (unsigned i = 0U; i < N; ++i) {
3505 if (i) {
3506 callbuf << ',';
3507 if (i % 2) {
3508 callbuf << ' ';
3509 } else {
3510 callbuf << "\n";
3511 indent(callbuf, indent_level + 1);
3512 }
3513 }
3514 const ParmVarDecl* PVD = FD->getNonObjectParameter(i);
3515 QualType Ty = PVD->getType();
3516 QualType QT = Ty.getCanonicalType();
3517 std::string arg_type;
3518 ASTContext& C = FD->getASTContext();
3519 get_type_as_string(QT, arg_type, C, C.getPrintingPolicy());
3520 callbuf << arg_type;
3521 }
3522 if (FD->isVariadic())
3523 callbuf << ", ...";
3524 callbuf << ")";
3525 }
3526
3527 callbuf << ")";
3528 }
3529
3530 if (const auto* MD = dyn_cast<CXXMethodDecl>(FD)) {
3531 // This is a class, struct, or union member.
3532 // An rvalue-ref-qualified method must be called on an rvalue: bind the
3533 // receiver with static_cast<T&&>. Covers `f() &&` and `this T&&` (the
3534 // latter leaves getRefQualifier() == RQ_None).
3535 bool rvalue_ref = MD->getRefQualifier() == clang::RQ_RValue ||
3536 (MD->hasCXXExplicitFunctionObjectParameter() &&
3537 MD->getParamDecl(0)->getType()->isRValueReferenceType());
3538 if (rvalue_ref)
3539 callbuf << "static_cast<" << class_name << "&&>(*(" << class_name
3540 << "*)obj).";
3541 else if (MD->isConst())
3542 callbuf << "((const " << class_name << "*)obj)->";
3543 else
3544 callbuf << "((" << class_name << "*)obj)->";
3545
3546 if (op_flag)
3547 callbuf << class_name << "::";
3548 } else if (isa<NamedDecl>(get_non_transparent_decl_context(FD))) {
3549 // This is a namespace member.
3550 if (op_flag || N <= 1)
3551 callbuf << class_name << "::";
3552 }
3553 // callbuf << fMethod->Name() << "(";
3554 {
3555 std::string name;
3556 {
3557 std::string complete_name;
3558 llvm::raw_string_ostream stream(complete_name);
3559 PrintingPolicy PP = FD->getASTContext().getPrintingPolicy();
3560 PP.FullyQualifiedName = true;
3561 PP.SuppressUnwrittenScope = true;
3562 PP.Suppress_Elab = true;
3563 FD->getNameForDiagnostic(stream, PP,
3564 /*Qualified=*/false);
3565 name = complete_name;
3566
3567 // If a template has consecutive parameter packs, then it is impossible to
3568 // use the explicit name in the wrapper, since the TyRef deduction is what
3569 // determines the split of the packs. Instead, we'll revert to the
3570 // non-templated function name and hope that the TyRef casts in the
3571 // wrapper will suffice.
3572 std::string simple_name = FD->getNameAsString();
3573 if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
3574 const auto* FTDecl =
3575 llvm::dyn_cast<FunctionTemplateDecl>(FD->getPrimaryTemplate());
3576 if (FTDecl) {
3577 auto* templateParms = FTDecl->getTemplateParameters();
3578 int numPacks = 0;
3579 for (size_t iParam = 0, nParams = templateParms->size();
3580 iParam < nParams; ++iParam) {
3581 if (templateParms->getParam(iParam)->isTemplateParameterPack())
3582 numPacks += 1;
3583 else
3584 numPacks = 0;
3585 }
3586 if (numPacks > 1) {
3587 name = simple_name;
3588 }
3589 }
3590 }
3591 if (FD->isOverloadedOperator())
3592 name = simple_name;
3593 }
3594 if (op_flag || N <= 1)
3595 callbuf << name;
3596 }
3597 if (ShouldCastFunction)
3598 callbuf << ")";
3599
3600 callbuf << "(";
3601 for (unsigned i = 0U; i < N; ++i) {
3602 const ParmVarDecl* PVD = FD->getNonObjectParameter(i);
3603 QualType Ty = PVD->getType();
3604 QualType QT = Ty.getCanonicalType();
3605 std::string type_name;
3606 EReferenceType refType = kNotReference;
3607 bool isPointer = false;
3608 collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
3609 isPointer, indent_level, true);
3610
3611 if (i) {
3612 if (op_flag) {
3613 callbuf << ", ";
3614 } else {
3615 callbuf << ' '
3616 << clang::getOperatorSpelling(FD->getOverloadedOperator())
3617 << ' ';
3618 }
3619 }
3620
3621 CXXRecordDecl* rtdecl = QT->getAsCXXRecordDecl();
3622 if (refType != kNotReference) {
3623 callbuf << "(" << type_name.c_str()
3624 << (refType == kLValueReference ? "&" : "&&") << ")*("
3625 << type_name.c_str() << "*)args[" << i << "]";
3626 } else if (isPointer) {
3627 callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
3628 } else if (rtdecl &&
3629 (rtdecl->hasTrivialCopyConstructor() &&
3630 !rtdecl->hasSimpleCopyConstructor()) &&
3631 rtdecl->hasMoveConstructor()) {
3632 // By-value construction; this may either copy or move, but there is no
3633 // information here in terms of intent. Thus, simply assume that the
3634 // intent is to move if there is no viable copy constructor (ie. if the
3635 // code would otherwise fail to even compile). There does not appear to be
3636 // a simple way of determining whether a viable copy constructor exists,
3637 // so check for the most common case: the trivial one, but not uniquely
3638 // available, while there is a move constructor.
3639
3640 // Move construction as needed for classes (note that this is
3641 // implicit). Emit `std::move`'s expansion directly rather than the
3642 // name: a cast to T&& is the definition of std::move for
3643 // non-reference T ([utility.swap]), and this avoids pulling
3644 // <utility> into the user's TU just to obtain the name. It also
3645 // sidesteps the `getSema().getStdNamespace()->lookup(...)` call,
3646 // which dereferences a nullptr when no `std::` has been parsed
3647 // yet in this interpreter's TU.
3648 callbuf << "static_cast<" << type_name.c_str() << "&&>(*("
3649 << type_name.c_str() << "*)args[" << i << "])";
3650 } else {
3651 // pointer falls back to non-pointer case; the argument preserves
3652 // the "pointerness" (i.e. doesn't reference the value).
3653 callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
3654 }
3655 }
3656 callbuf << ")";
3657}
3658
3659void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
3660 const std::string& class_name,
3661 std::ostringstream& buf, int indent_level) {
3662 // Make a code string that follows this pattern:
3663 //
3664 // Array new if nary has been passed, and nargs is 0 (must be default ctor)
3665 // if (nary) {
3666 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary] :
3667 // new ClassName[nary];
3668 // }
3669 // else {
3670 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
3671 // : new ClassName(args...);
3672 // }
3673 {
3674 std::ostringstream typedefbuf;
3675 std::ostringstream callbuf;
3676 //
3677 // Write the return value assignment part.
3678 //
3679 indent(callbuf, indent_level);
3680 const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
3681
3682 // Activate this block only if array new is possible
3683 // if (nary) {
3684 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary]
3685 // : new ClassName[nary];
3686 // }
3687 // else {
3688 if (CD->isDefaultConstructor()) {
3689 callbuf << "if (nary > 1) {\n";
3690 indent(callbuf, indent_level);
3691 callbuf << "(*(" << class_name << "**)ret) = ";
3692 callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
3693 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
3694 true);
3695
3696 callbuf << ": new ";
3697 //
3698 // Write the actual expression.
3699 //
3700 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
3701 true);
3702 //
3703 // End the new expression statement.
3704 //
3705 callbuf << ";\n";
3706 indent(callbuf, indent_level);
3707 callbuf << "}\n";
3708 callbuf << "else {\n";
3709 }
3710
3711 // Standard branch:
3712 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
3713 // : new ClassName(args...);
3714 indent(callbuf, indent_level);
3715 callbuf << "(*(" << class_name << "**)ret) = ";
3716 callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
3717 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
3718
3719 callbuf << ": new ";
3720 //
3721 // Write the actual expression.
3722 //
3723 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
3724 //
3725 // End the new expression statement.
3726 //
3727 callbuf << ";\n";
3728 indent(callbuf, --indent_level);
3729 if (CD->isDefaultConstructor())
3730 callbuf << "}\n";
3731#if __has_feature(memory_sanitizer)
3732 // Outside the if/else so the array-new (nary > 1) and single-new
3733 // branches are both covered.
3734 indent(callbuf, indent_level);
3735 callbuf << "__msan_unpoison(*(void**)ret, sizeof(" << class_name
3736 << ") * (nary > 1 ? nary : 1));\n";
3737#endif
3738
3739 //
3740 // Output the whole new expression and return statement.
3741 //
3742 buf << typedefbuf.str() << callbuf.str();
3743 }
3744}
3745
3746void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD,
3747 const unsigned N, const std::string& class_name,
3748 std::ostringstream& buf, int indent_level) {
3749 // Make a code string that follows this pattern:
3750 //
3751 // if (ret) {
3752 // new (ret) (return_type) ((class_name*)obj)->func(args...);
3753 // }
3754 // else {
3755 // (void)(((class_name*)obj)->func(args...));
3756 // }
3757 //
3758 if (const auto* CD = dyn_cast<CXXConstructorDecl>(FD)) {
3759 if (N <= 1 && llvm::isa<UsingShadowDecl>(FD)) {
3760 auto SpecMemKind = I.getCI()->getSema().getSpecialMember(CD);
3761 if ((N == 0 && SpecMemKind == CXXSpecialMemberKind::DefaultConstructor) ||
3762 (N == 1 && (SpecMemKind == CXXSpecialMemberKind::CopyConstructor ||
3763 SpecMemKind == CXXSpecialMemberKind::MoveConstructor))) {
3764 // Using declarations cannot inject special members; do not call
3765 // them as such. This might happen by using `Base(Base&, int = 12)`,
3766 // which is fine to be called as `Derived d(someBase, 42)` but not
3767 // as copy constructor of `Derived`.
3768 return;
3769 }
3770 }
3771 make_narg_ctor_with_return(FD, N, class_name, buf, indent_level);
3772 return;
3773 }
3774 QualType QT = FD->getReturnType();
3775 if (QT->isVoidType()) {
3776 std::ostringstream typedefbuf;
3777 std::ostringstream callbuf;
3778 indent(callbuf, indent_level);
3779 make_narg_call(FD, "void", N, typedefbuf, callbuf, class_name,
3780 indent_level);
3781 callbuf << ";\n";
3782 indent(callbuf, indent_level);
3783 callbuf << "return;\n";
3784 buf << typedefbuf.str() << callbuf.str();
3785 } else {
3786 indent(buf, indent_level);
3787
3788 std::string type_name;
3789 EReferenceType refType = kNotReference;
3790 bool isPointer = false;
3791
3792 std::ostringstream typedefbuf;
3793 std::ostringstream callbuf;
3794
3795 collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
3796 isPointer, indent_level, false);
3797
3798 buf << typedefbuf.str();
3799
3800 buf << "if (ret) {\n";
3801 ++indent_level;
3802 {
3803 //
3804 // Write the placement part of the placement new.
3805 //
3806 indent(callbuf, indent_level);
3807 callbuf << "new (ret) ";
3808 //
3809 // Write the TyRef part of the placement new.
3810 //
3811 callbuf << "(" << type_name.c_str();
3812 if (refType != kNotReference) {
3813 callbuf << "*) (&";
3814 type_name += "&";
3815 } else if (isPointer) {
3816 callbuf << "*) (";
3817 type_name += "*";
3818 } else {
3819 callbuf << ") (";
3820 }
3821 //
3822 // Write the actual function call.
3823 //
3824 make_narg_call(FD, type_name, N, typedefbuf, callbuf, class_name,
3825 indent_level);
3826 //
3827 // End the placement new.
3828 //
3829 callbuf << ");\n";
3830#if __has_feature(memory_sanitizer)
3831 indent(callbuf, indent_level);
3832 callbuf << "__msan_unpoison(ret, sizeof(" << type_name << "));\n";
3833#endif
3834 indent(callbuf, indent_level);
3835 callbuf << "return;\n";
3836 //
3837 // Output the whole placement new expression and return statement.
3838 //
3839 buf << typedefbuf.str() << callbuf.str();
3840 }
3841 --indent_level;
3842 indent(buf, indent_level);
3843 buf << "}\n";
3844 indent(buf, indent_level);
3845 buf << "else {\n";
3846 ++indent_level;
3847 {
3848 std::ostringstream typedefbuf;
3849 std::ostringstream callbuf;
3850 indent(callbuf, indent_level);
3851 callbuf << "(void)(";
3852 make_narg_call(FD, type_name, N, typedefbuf, callbuf, class_name,
3853 indent_level);
3854 callbuf << ");\n";
3855 indent(callbuf, indent_level);
3856 callbuf << "return;\n";
3857 buf << typedefbuf.str() << callbuf.str();
3858 }
3859 --indent_level;
3860 indent(buf, indent_level);
3861 buf << "}\n";
3862 }
3863}
3864
3865int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
3866 std::string& wrapper_name, std::string& wrapper) {
3867 assert(FD && "generate_wrapper called without a function decl!");
3868 ASTContext& Context = FD->getASTContext();
3869 //
3870 // Get the class or namespace name.
3871 //
3872 std::string class_name;
3873 const clang::DeclContext* DC = get_non_transparent_decl_context(FD);
3874 GetDeclName(cast<Decl>(DC), Context, class_name);
3875 //
3876 // Check to make sure that we can
3877 // instantiate and codegen this function.
3878 //
3879 bool needInstantiation = false;
3880 const FunctionDecl* Definition = 0;
3882 if (!FD->isDefined(Definition)) {
3883 FunctionDecl::TemplatedKind TK = FD->getTemplatedKind();
3884 switch (TK) {
3885 case FunctionDecl::TK_NonTemplate: {
3886 // Ordinary function, not a template specialization.
3887 // Note: This might be ok, the body might be defined
3888 // in a library, and all we have seen is the
3889 // header file.
3890 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3891 // "Cannot make wrapper for a function which is "
3892 // "declared but not defined!";
3893 // return 0;
3894 } break;
3895 case FunctionDecl::TK_FunctionTemplate: {
3896 // This decl is actually a function template,
3897 // not a function at all.
3898 llvm::errs() << "TClingCallFunc::make_wrapper"
3899 << ":"
3900 << "Cannot make wrapper for a function template!";
3901 return 0;
3902 } break;
3903 case FunctionDecl::TK_MemberSpecialization: {
3904 // This function is the result of instantiating an ordinary
3905 // member function of a class template, or of instantiating
3906 // an ordinary member function of a class member of a class
3907 // template, or of specializing a member function template
3908 // of a class template, or of specializing a member function
3909 // template of a class member of a class template.
3910 if (!FD->isTemplateInstantiation()) {
3911 // We are either TSK_Undeclared or
3912 // TSK_ExplicitSpecialization.
3913 // Note: This might be ok, the body might be defined
3914 // in a library, and all we have seen is the
3915 // header file.
3916 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3917 // "Cannot make wrapper for a function template "
3918 // "explicit specialization which is declared "
3919 // "but not defined!";
3920 // return 0;
3921 break;
3922 }
3923 const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern();
3924 if (!Pattern) {
3925 llvm::errs() << "TClingCallFunc::make_wrapper"
3926 << ":"
3927 << "Cannot make wrapper for a member function "
3928 "instantiation with no pattern!";
3929 return 0;
3930 }
3931 FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
3932 TemplateSpecializationKind PTSK =
3933 Pattern->getTemplateSpecializationKind();
3934 if (
3935 // The pattern is an ordinary member function.
3936 (PTK == FunctionDecl::TK_NonTemplate) ||
3937 // The pattern is an explicit specialization, and
3938 // so is not a template.
3939 ((PTK != FunctionDecl::TK_FunctionTemplate) &&
3940 ((PTSK == TSK_Undeclared) ||
3941 (PTSK == TSK_ExplicitSpecialization)))) {
3942 // Note: This might be ok, the body might be defined
3943 // in a library, and all we have seen is the
3944 // header file.
3945 break;
3946 } else if (!Pattern->hasBody()) {
3947 llvm::errs() << "TClingCallFunc::make_wrapper"
3948 << ":"
3949 << "Cannot make wrapper for a member function "
3950 "instantiation with no body!";
3951 return 0;
3952 }
3953 if (FD->isImplicitlyInstantiable()) {
3954 needInstantiation = true;
3955 }
3956 } break;
3957 case FunctionDecl::TK_FunctionTemplateSpecialization: {
3958 // This function is the result of instantiating a function
3959 // template or possibly an explicit specialization of a
3960 // function template. Could be a namespace DRef function or a
3961 // member function.
3962 if (!FD->isTemplateInstantiation()) {
3963 // We are either TSK_Undeclared or
3964 // TSK_ExplicitSpecialization.
3965 // Note: This might be ok, the body might be defined
3966 // in a library, and all we have seen is the
3967 // header file.
3968 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3969 // "Cannot make wrapper for a function template "
3970 // "explicit specialization which is declared "
3971 // "but not defined!";
3972 // return 0;
3973 break;
3974 }
3975 const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern();
3976 if (!Pattern) {
3977 llvm::errs() << "TClingCallFunc::make_wrapper"
3978 << ":"
3979 << "Cannot make wrapper for a function template"
3980 "instantiation with no pattern!";
3981 return 0;
3982 }
3983 FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
3984 TemplateSpecializationKind PTSK =
3985 Pattern->getTemplateSpecializationKind();
3986 if (
3987 // The pattern is an ordinary member function.
3988 (PTK == FunctionDecl::TK_NonTemplate) ||
3989 // The pattern is an explicit specialization, and
3990 // so is not a template.
3991 ((PTK != FunctionDecl::TK_FunctionTemplate) &&
3992 ((PTSK == TSK_Undeclared) ||
3993 (PTSK == TSK_ExplicitSpecialization)))) {
3994 // Note: This might be ok, the body might be defined
3995 // in a library, and all we have seen is the
3996 // header file.
3997 break;
3998 }
3999 if (!GetFunctionAddress(FD)) {
4000 if (!Pattern->hasBody()) {
4001 llvm::errs() << "TClingCallFunc::make_wrapper"
4002 << ":"
4003 << "Cannot make wrapper for a function template "
4004 << "instantiation with no body!";
4005 return 0;
4006 }
4007 if (FD->isImplicitlyInstantiable()) {
4008 needInstantiation = true;
4009 }
4010 }
4011 } break;
4012 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
4013 // This function is the result of instantiating or
4014 // specializing a member function of a class template,
4015 // or a member function of a class member of a class template,
4016 // or a member function template of a class template, or a
4017 // member function template of a class member of a class
4018 // template where at least some part of the function is
4019 // dependent on a template argument.
4020 if (!FD->isTemplateInstantiation()) {
4021 // We are either TSK_Undeclared or
4022 // TSK_ExplicitSpecialization.
4023 // Note: This might be ok, the body might be defined
4024 // in a library, and all we have seen is the
4025 // header file.
4026 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
4027 // "Cannot make wrapper for a dependent function "
4028 // "template explicit specialization which is declared "
4029 // "but not defined!";
4030 // return 0;
4031 break;
4032 }
4033 const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern();
4034 if (!Pattern) {
4035 llvm::errs() << "TClingCallFunc::make_wrapper"
4036 << ":"
4037 << "Cannot make wrapper for a dependent function template"
4038 "instantiation with no pattern!";
4039 return 0;
4040 }
4041 FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
4042 TemplateSpecializationKind PTSK =
4043 Pattern->getTemplateSpecializationKind();
4044 if (
4045 // The pattern is an ordinary member function.
4046 (PTK == FunctionDecl::TK_NonTemplate) ||
4047 // The pattern is an explicit specialization, and
4048 // so is not a template.
4049 ((PTK != FunctionDecl::TK_FunctionTemplate) &&
4050 ((PTSK == TSK_Undeclared) ||
4051 (PTSK == TSK_ExplicitSpecialization)))) {
4052 // Note: This might be ok, the body might be defined
4053 // in a library, and all we have seen is the
4054 // header file.
4055 break;
4056 }
4057 if (!Pattern->hasBody()) {
4058 llvm::errs() << "TClingCallFunc::make_wrapper"
4059 << ":"
4060 << "Cannot make wrapper for a dependent function template"
4061 "instantiation with no body!";
4062 return 0;
4063 }
4064 if (FD->isImplicitlyInstantiable()) {
4065 needInstantiation = true;
4066 }
4067 } break;
4068 default: {
4069 // Will only happen if clang implementation changes.
4070 // Protect ourselves in case that happens.
4071 llvm::errs() << "TClingCallFunc::make_wrapper"
4072 << ":"
4073 << "Unhandled template kind!";
4074 return 0;
4075 } break;
4076 }
4077 // We do not set needInstantiation to true in these cases:
4078 //
4079 // isInvalidDecl()
4080 // TSK_Undeclared
4081 // TSK_ExplicitInstantiationDefinition
4082 // TSK_ExplicitSpecialization && !getClassScopeSpecializationPattern()
4083 // TSK_ExplicitInstantiationDeclaration &&
4084 // getTemplateInstantiationPattern() &&
4085 // PatternDecl->hasBody() &&
4086 // !PatternDecl->isInlined()
4087 //
4088 // Set it true in these cases:
4089 //
4090 // TSK_ImplicitInstantiation
4091 // TSK_ExplicitInstantiationDeclaration && (!getPatternDecl() ||
4092 // !PatternDecl->hasBody() || PatternDecl->isInlined())
4093 //
4094 }
4095 if (needInstantiation) {
4096 clang::FunctionDecl* FDmod = const_cast<clang::FunctionDecl*>(FD);
4098
4099 if (!FD->isDefined(Definition)) {
4100 llvm::errs() << "TClingCallFunc::make_wrapper"
4101 << ":"
4102 << "Failed to force template instantiation!";
4103 return 0;
4104 }
4105 }
4106 if (Definition) {
4107 FunctionDecl::TemplatedKind TK = Definition->getTemplatedKind();
4108 switch (TK) {
4109 case FunctionDecl::TK_NonTemplate: {
4110 // Ordinary function, not a template specialization.
4111 if (Definition->isDeleted()) {
4112 llvm::errs() << "TClingCallFunc::make_wrapper"
4113 << ":"
4114 << "Cannot make wrapper for a deleted function!";
4115 return 0;
4116 } else if (Definition->isLateTemplateParsed()) {
4117 llvm::errs() << "TClingCallFunc::make_wrapper"
4118 << ":"
4119 << "Cannot make wrapper for a late template parsed "
4120 "function!";
4121 return 0;
4122 }
4123 // else if (Definition->isDefaulted()) {
4124 // // Might not have a body, but we can still use it.
4125 //}
4126 // else {
4127 // // Has a body.
4128 //}
4129 } break;
4130 case FunctionDecl::TK_FunctionTemplate: {
4131 // This decl is actually a function template,
4132 // not a function at all.
4133 llvm::errs() << "TClingCallFunc::make_wrapper"
4134 << ":"
4135 << "Cannot make wrapper for a function template!";
4136 return 0;
4137 } break;
4138 case FunctionDecl::TK_MemberSpecialization: {
4139 // This function is the result of instantiating an ordinary
4140 // member function of a class template or of a member class
4141 // of a class template.
4142 if (Definition->isDeleted()) {
4143 llvm::errs() << "TClingCallFunc::make_wrapper"
4144 << ":"
4145 << "Cannot make wrapper for a deleted member function "
4146 "of a specialization!";
4147 return 0;
4148 } else if (Definition->isLateTemplateParsed()) {
4149 llvm::errs() << "TClingCallFunc::make_wrapper"
4150 << ":"
4151 << "Cannot make wrapper for a late template parsed "
4152 "member function of a specialization!";
4153 return 0;
4154 }
4155 // else if (Definition->isDefaulted()) {
4156 // // Might not have a body, but we can still use it.
4157 //}
4158 // else {
4159 // // Has a body.
4160 //}
4161 } break;
4162 case FunctionDecl::TK_FunctionTemplateSpecialization: {
4163 // This function is the result of instantiating a function
4164 // template or possibly an explicit specialization of a
4165 // function template. Could be a namespace DRef function or a
4166 // member function.
4167 if (Definition->isDeleted()) {
4168 llvm::errs() << "TClingCallFunc::make_wrapper"
4169 << ":"
4170 << "Cannot make wrapper for a deleted function "
4171 "template specialization!";
4172 return 0;
4173 } else if (Definition->isLateTemplateParsed()) {
4174 llvm::errs() << "TClingCallFunc::make_wrapper"
4175 << ":"
4176 << "Cannot make wrapper for a late template parsed "
4177 "function template specialization!";
4178 return 0;
4179 }
4180 // else if (Definition->isDefaulted()) {
4181 // // Might not have a body, but we can still use it.
4182 //}
4183 // else {
4184 // // Has a body.
4185 //}
4186 } break;
4187 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
4188 // This function is the result of instantiating or
4189 // specializing a member function of a class template,
4190 // or a member function of a class member of a class template,
4191 // or a member function template of a class template, or a
4192 // member function template of a class member of a class
4193 // template where at least some part of the function is
4194 // dependent on a template argument.
4195 if (Definition->isDeleted()) {
4196 llvm::errs() << "TClingCallFunc::make_wrapper"
4197 << ":"
4198 << "Cannot make wrapper for a deleted dependent function "
4199 "template specialization!";
4200 return 0;
4201 } else if (Definition->isLateTemplateParsed()) {
4202 llvm::errs() << "TClingCallFunc::make_wrapper"
4203 << ":"
4204 << "Cannot make wrapper for a late template parsed "
4205 "dependent function template specialization!";
4206 return 0;
4207 }
4208 // else if (Definition->isDefaulted()) {
4209 // // Might not have a body, but we can still use it.
4210 //}
4211 // else {
4212 // // Has a body.
4213 //}
4214 } break;
4215 default: {
4216 // Will only happen if clang implementation changes.
4217 // Protect ourselves in case that happens.
4218 llvm::errs() << "TClingCallFunc::make_wrapper"
4219 << ":"
4220 << "Unhandled template kind!";
4221 return 0;
4222 } break;
4223 }
4224 }
4225 // A C++23 explicit object parameter is bound via the `obj->` receiver of the
4226 // emitted member call, not from the args[] array, so it is excluded from the
4227 // wrapper's argument arity (see make_narg_call).
4228 unsigned min_args = FD->getMinRequiredExplicitArguments();
4229 unsigned num_params = FD->getNumNonObjectParams();
4230 //
4231 // Make the wrapper name.
4232 //
4233 {
4234 std::ostringstream buf;
4235 buf << "__jc";
4236 // const auto* ND = dyn_cast<NamedDecl>(FD);
4237 // std::string mn;
4238 // fInterp->maybeMangleDeclName(ND, mn);
4239 // buf << '_' << mn;
4240 buf << '_' << gWrapperSerial++;
4241 wrapper_name = buf.str();
4242 }
4243 //
4244 // Write the wrapper code.
4245 // FIXME: this should be synthesized into the AST!
4246 //
4247 int indent_level = 0;
4248 std::ostringstream buf;
4249 buf << "#pragma clang diagnostic push\n"
4250 "#pragma clang diagnostic ignored \"-Wformat-security\"\n";
4251#if __has_feature(memory_sanitizer)
4252 // Declared (not #include'd) so the wrapper compiles with no need
4253 // for sanitizer headers in the JIT search path.
4254 buf << "extern \"C\" void __msan_unpoison(const volatile void*, "
4255 "unsigned long);\n";
4256#endif
4257 buf << "__attribute__((used)) "
4258 "__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
4259 "extern \"C\" void ";
4260 buf << wrapper_name;
4261 if (Cpp::IsConstructor(wrap<ConstFuncRef>(FD))) {
4262 buf << "(void* ret, unsigned long nary, unsigned long nargs, void** args, "
4263 "void* is_arena)\n"
4264 "{\n";
4265 } else
4266 buf << "(void* obj, unsigned long nargs, void** args, void* ret)\n"
4267 "{\n";
4268
4269 ++indent_level;
4270 if (min_args == num_params) {
4271 // No parameters with defaults.
4272 make_narg_call_with_return(I, FD, num_params, class_name, buf,
4273 indent_level);
4274 } else {
4275 // We need one function call clause compiled for every
4276 // possible number of arguments per call.
4277 for (unsigned N = min_args; N <= num_params; ++N) {
4278 indent(buf, indent_level);
4279 buf << "if (nargs == " << N << ") {\n";
4280 ++indent_level;
4281 make_narg_call_with_return(I, FD, N, class_name, buf, indent_level);
4282 --indent_level;
4283 indent(buf, indent_level);
4284 buf << "}\n";
4285 }
4286 }
4287 --indent_level;
4288 buf << "}\n"
4289 "#pragma clang diagnostic pop";
4290 wrapper = buf.str();
4291 return 1;
4292}
4293
4294JitCall::GenericCall make_wrapper(compat::Interpreter& I,
4295 const FunctionDecl* FD) {
4296 auto& WrapperStore = getInterpInfo(&I).WrapperStore;
4297
4298 auto R = WrapperStore.find(FD);
4299 if (R != WrapperStore.end())
4300 return (JitCall::GenericCall)R->second;
4301
4302 std::string wrapper_name;
4303 std::string wrapper_code;
4304
4305 if (get_wrapper_code(I, FD, wrapper_name, wrapper_code) == 0)
4306 return 0;
4307
4308 // Log the wrapper source for the crash reproducer.
4309 if (auto* TI = CppInterOp::Tracing::TheTraceInfo) {
4310 std::string FuncName;
4311 llvm::raw_string_ostream FNS(FuncName);
4312 FD->getNameForDiagnostic(FNS, FD->getASTContext().getPrintingPolicy(),
4313 /*Qualified=*/true);
4314 TI->appendToLog(" // === Wrapper for " + FuncName + " ===");
4315 // Emit each line of the wrapper source as a comment.
4316 llvm::StringRef WC(wrapper_code);
4317 while (!WC.empty()) {
4318 auto [Line, Rest] = WC.split('\n');
4319 if (!Line.empty())
4320 TI->appendToLog((" // " + Line).str());
4321 WC = Rest;
4322 }
4323 TI->appendToLog(" // === End wrapper ===");
4324 }
4325
4326 //
4327 // Compile the wrapper code.
4328 //
4329 bool withAccessControl = true;
4330 // We should be able to call private default constructors.
4331 if (auto Ctor = dyn_cast<CXXConstructorDecl>(FD))
4332 withAccessControl = !Ctor->isDefaultConstructor();
4333 void* wrapper =
4334 compile_wrapper(I, wrapper_name, wrapper_code, withAccessControl);
4335 if (wrapper) {
4336 WrapperStore.insert(std::make_pair(FD, wrapper));
4337 } else {
4338 llvm::errs() << "TClingCallFunc::make_wrapper"
4339 << ":"
4340 << "Failed to compile\n"
4341 << "==== SOURCE BEGIN ====\n"
4342 << wrapper_code << "\n"
4343 << "==== SOURCE END ====\n";
4344 }
4345 LLVM_DEBUG(dbgs() << "Compiled '" << (wrapper ? "" : "un")
4346 << "successfully:\n"
4347 << wrapper_code << "'\n");
4348 return (JitCall::GenericCall)wrapper;
4349}
4350
4351// FIXME: Sink in the code duplication from get_wrapper_code.
4352static std::string PrepareStructorWrapper(const Decl* D,
4353 const char* wrapper_prefix,
4354 std::string& class_name) {
4355 ASTContext& Context = D->getASTContext();
4356 GetDeclName(D, Context, class_name);
4357
4358 //
4359 // Make the wrapper name.
4360 //
4361 std::string wrapper_name;
4362 {
4363 std::ostringstream buf;
4364 buf << wrapper_prefix;
4365 // const auto* ND = dyn_cast<NamedDecl>(FD);
4366 // string mn;
4367 // fInterp->maybeMangleDeclName(ND, mn);
4368 // buf << '_dtor_' << mn;
4369 buf << '_' << gWrapperSerial++;
4370 wrapper_name = buf.str();
4371 }
4372
4373 return wrapper_name;
4374}
4375
4376static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp,
4377 const Decl* D) {
4378 // Make a code string that follows this pattern:
4379 //
4380 // void
4381 // unique_wrapper_ddd(void* obj, unsigned long nary, int withFree)
4382 // {
4383 // if (withFree) {
4384 // if (!nary) {
4385 // delete (ClassName*) obj;
4386 // }
4387 // else {
4388 // delete[] (ClassName*) obj;
4389 // }
4390 // }
4391 // else {
4392 // typedef ClassName DtorName;
4393 // if (!nary) {
4394 // ((ClassName*)obj)->~DtorName();
4395 // }
4396 // else {
4397 // for (unsigned long i = nary - 1; i > -1; --i) {
4398 // (((ClassName*)obj)+i)->~DtorName();
4399 // }
4400 // }
4401 // }
4402 // }
4403 //
4404 //--
4405
4406 auto& DtorWrapperStore = getInterpInfo(&interp).DtorWrapperStore;
4407
4408 auto I = DtorWrapperStore.find(D);
4409 if (I != DtorWrapperStore.end())
4410 return (JitCall::DestructorCall)I->second;
4411
4412 //
4413 // Make the wrapper name.
4414 //
4415 std::string class_name;
4416 std::string wrapper_name = PrepareStructorWrapper(D, "__dtor", class_name);
4417 //
4418 // Write the wrapper code.
4419 //
4420 int indent_level = 0;
4421 std::ostringstream buf;
4422#if CPPINTEROP_ASAN_BUILD
4423 // ASan-only: the ORC JIT's resolution of the delete-expression below
4424 // does not always route through libasan's operator-delete interposer
4425 // (observed for classes with an out-of-line destructor), leaving the
4426 // matching operator-new allocation live in LSan's shadow after the
4427 // real free. Call __lsan_ignore_object on the object first so LSan
4428 // treats the allocation as intentional. Real user-side leaks never
4429 // reach this wrapper and stay fully visible. Exercised by
4430 // FunctionReflection_GetFunctionCallWrapper in the unit tests;
4431 // removing this block makes that test report a leak under LSan CI.
4432 buf << "extern \"C\" void __lsan_ignore_object(const void*);\n";
4433#endif
4434 buf << "__attribute__((used)) ";
4435 buf << "extern \"C\" void ";
4436 buf << wrapper_name;
4437 buf << "(void* obj, unsigned long nary, int withFree)\n";
4438 buf << "{\n";
4439 // if (withFree) {
4440 // __lsan_ignore_object(obj); // ASan builds only
4441 // if (!nary) {
4442 // delete (ClassName*) obj;
4443 // }
4444 // else {
4445 // delete[] (ClassName*) obj;
4446 // }
4447 // }
4448 ++indent_level;
4449 indent(buf, indent_level);
4450 buf << "if (withFree) {\n";
4451 ++indent_level;
4452#if CPPINTEROP_ASAN_BUILD
4453 indent(buf, indent_level);
4454 buf << "__lsan_ignore_object(obj);\n";
4455#endif
4456 indent(buf, indent_level);
4457 buf << "if (!nary) {\n";
4458 ++indent_level;
4459 indent(buf, indent_level);
4460 buf << "delete (" << class_name << "*) obj;\n";
4461 --indent_level;
4462 indent(buf, indent_level);
4463 buf << "}\n";
4464 indent(buf, indent_level);
4465 buf << "else {\n";
4466 ++indent_level;
4467 indent(buf, indent_level);
4468 buf << "delete[] (" << class_name << "*) obj;\n";
4469 --indent_level;
4470 indent(buf, indent_level);
4471 buf << "}\n";
4472 --indent_level;
4473 indent(buf, indent_level);
4474 buf << "}\n";
4475 // else {
4476 // typedef ClassName Nm;
4477 // if (!nary) {
4478 // ((Nm*)obj)->~Nm();
4479 // }
4480 // else {
4481 // for (unsigned long i = nary - 1; i > -1; --i) {
4482 // (((Nm*)obj)+i)->~Nm();
4483 // }
4484 // }
4485 // }
4486 indent(buf, indent_level);
4487 buf << "else {\n";
4488 ++indent_level;
4489 indent(buf, indent_level);
4490 buf << "typedef " << class_name << " Nm;\n";
4491 buf << "if (!nary) {\n";
4492 ++indent_level;
4493 indent(buf, indent_level);
4494 buf << "((Nm*)obj)->~Nm();\n";
4495 --indent_level;
4496 indent(buf, indent_level);
4497 buf << "}\n";
4498 indent(buf, indent_level);
4499 buf << "else {\n";
4500 ++indent_level;
4501 indent(buf, indent_level);
4502 buf << "do {\n";
4503 ++indent_level;
4504 indent(buf, indent_level);
4505 buf << "(((Nm*)obj)+(--nary))->~Nm();\n";
4506 --indent_level;
4507 indent(buf, indent_level);
4508 buf << "} while (nary);\n";
4509 --indent_level;
4510 indent(buf, indent_level);
4511 buf << "}\n";
4512 --indent_level;
4513 indent(buf, indent_level);
4514 buf << "}\n";
4515 // End wrapper.
4516 --indent_level;
4517 buf << "}\n";
4518 // Done.
4519 std::string wrapper(buf.str());
4520 // fprintf(stderr, "%s\n", wrapper.c_str());
4521 //
4522 // Compile the wrapper code.
4523 //
4524 void* F = compile_wrapper(interp, wrapper_name, wrapper,
4525 /*withAccessControl=*/false);
4526 if (F) {
4527 DtorWrapperStore.insert(std::make_pair(D, F));
4528 } else {
4529 llvm::errs() << "make_dtor_wrapper"
4530 << "Failed to compile\n"
4531 << "==== SOURCE BEGIN ====\n"
4532 << wrapper << "\n ==== SOURCE END ====";
4533 }
4534 LLVM_DEBUG(dbgs() << "Compiled '" << (F ? "" : "un") << "successfully:\n"
4535 << wrapper << "'\n");
4536 return (JitCall::DestructorCall)F;
4537}
4538#undef DEBUG_TYPE
4539} // namespace
4540 // End of JitCall Helper Functions
4541
4542CPPINTEROP_API JitCall MakeFunctionCallable(InterpRef I, ConstFuncRef func) {
4543 INTEROP_TRACE(I, func);
4544 const auto* D = unwrap<clang::Decl>(func);
4545 if (!D)
4546 return INTEROP_RETURN(JitCall{});
4547
4548 auto* interp = unwrap<compat::Interpreter>(I);
4549
4550 // FIXME: Unify with make_wrapper.
4551 if (const auto* Dtor = dyn_cast<CXXDestructorDecl>(D)) {
4552 if (auto Wrapper = make_dtor_wrapper(*interp, Dtor->getParent()))
4553 return INTEROP_RETURN(
4554 JitCall(JitCall::kDestructorCall, Wrapper, wrap<ConstFuncRef>(Dtor)));
4555 // FIXME: else error we failed to compile the wrapper.
4556 return INTEROP_RETURN(JitCall{});
4557 }
4558
4559 if (const auto* Ctor = dyn_cast<CXXConstructorDecl>(D)) {
4560 if (auto Wrapper = make_wrapper(*interp, cast<FunctionDecl>(D)))
4561 return INTEROP_RETURN(JitCall(JitCall::kConstructorCall, Wrapper,
4562 wrap<ConstFuncRef>(Ctor)));
4563 // FIXME: else error we failed to compile the wrapper.
4564 return INTEROP_RETURN(JitCall{});
4565 }
4566
4567 if (auto Wrapper = make_wrapper(*interp, cast<FunctionDecl>(D))) {
4568 return INTEROP_RETURN(JitCall(JitCall::kGenericCall, Wrapper,
4569 wrap<ConstFuncRef>(cast<FunctionDecl>(D))));
4570 }
4571 // FIXME: else error we failed to compile the wrapper.
4572 return INTEROP_RETURN(JitCall{});
4573}
4574
4575CPPINTEROP_API JitCall MakeFunctionCallable(ConstFuncRef func) {
4576 INTEROP_TRACE(func);
4578}
4579
4580namespace {
4581#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
4582bool DefineAbsoluteSymbol(compat::Interpreter& I, const char* unmangled_name,
4583 uint64_t address) {
4584 using namespace llvm;
4585 using namespace llvm::orc;
4586
4587 llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I);
4588 JITDylib& DyLib = *Jit.getProcessSymbolsJITDylib().get();
4589
4590 // mangleAndIntern applies the target DataLayout's symbol prefix
4591 // (leading `_` on Mach-O, no-op on ELF) so the registered key
4592 // matches what the JIT computes when it lowers an IR symbol
4593 // reference for lookup. Plain ES.intern() bypasses the prefix and
4594 // silently breaks lookup on Mach-O.
4595 llvm::orc::SymbolMap InjectedSymbols{
4596 {Jit.mangleAndIntern(unmangled_name),
4597 ExecutorSymbolDef(ExecutorAddr(address), JITSymbolFlags::Exported)}};
4598
4599 if (Error Err = DyLib.define(absoluteSymbols(InjectedSymbols))) {
4600 logAllUnhandledErrors(std::move(Err), errs(),
4601 "DefineAbsoluteSymbol error: ");
4602 return true;
4603 }
4604 return false;
4605}
4606#endif
4607
4608static std::string MakeResourcesPath() {
4609 StringRef Dir;
4610#ifdef LLVM_BINARY_DIR
4611 Dir = LLVM_BINARY_DIR;
4612#else
4613 // Dir is bin/ or lib/, depending on where BinaryPath is.
4614 void* MainAddr = (void*)(intptr_t)GetExecutablePath;
4615 std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr, MainAddr);
4616
4617 // build/tools/clang/unittests/Interpreter/Executable -> build/
4618 StringRef Dir = sys::path::parent_path(BinaryPath);
4619
4620 Dir = sys::path::parent_path(Dir);
4621 Dir = sys::path::parent_path(Dir);
4622 Dir = sys::path::parent_path(Dir);
4623 Dir = sys::path::parent_path(Dir);
4624 // Dir = sys::path::parent_path(Dir);
4625#endif // LLVM_BINARY_DIR
4626 llvm::SmallString<128> P(Dir);
4627 llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
4628 CLANG_VERSION_MAJOR_STRING);
4629 return std::string(P.str());
4630}
4631
4632void AddLibrarySearchPaths(const std::string& ResourceDir,
4634 // the resource-dir can be of the form
4635 // /prefix/lib/clang/XX or /prefix/lib/llvm-XX/lib/clang/XX
4636 // where XX represents version
4637 // the corresponing path we want to add are
4638 // /prefix/lib/clang/XX/lib, /prefix/lib/, and
4639 // /prefix/lib/llvm-XX/lib/clang/XX/lib, /prefix/lib/llvm-XX/lib/,
4640 // /prefix/lib/
4641 std::string path1 = ResourceDir + "/lib";
4642 I->getDynamicLibraryManager()->addSearchPath(path1, false, false);
4643 size_t pos = ResourceDir.rfind("/llvm-");
4644 if (pos != std::string::npos) {
4645 I->getDynamicLibraryManager()->addSearchPath(ResourceDir.substr(0, pos),
4646 false, false);
4647 }
4648 pos = ResourceDir.rfind("/clang");
4649 if (pos != std::string::npos) {
4650 I->getDynamicLibraryManager()->addSearchPath(ResourceDir.substr(0, pos),
4651 false, false);
4652 }
4653}
4654std::string ExtractArgument(const std::vector<const char*>& Args,
4655 const std::string& Arg) {
4656 size_t I = 0;
4657 for (auto i = Args.begin(); i != Args.end(); i++)
4658 if ((++I < Args.size()) && (*i == Arg))
4659 return *(++i);
4660 return "";
4661}
4662} // namespace
4663
4664///\returns 0 on success.
4665static bool exec(const char* cmd, std::vector<std::string>& outputs) {
4666#define DEBUG_TYPE "exec"
4667
4668 std::array<char, 256> buffer;
4669 struct file_deleter {
4670 void operator()(FILE* fp) { pclose(fp); }
4671 };
4672 std::unique_ptr<FILE, file_deleter> pipe{popen(cmd, "r")};
4673 LLVM_DEBUG(dbgs() << "Executing command '" << cmd << "'\n");
4674
4675 if (!pipe) {
4676 LLVM_DEBUG(dbgs() << "Execute failed!\n");
4677 perror("exec: ");
4678 return false;
4679 }
4680
4681 LLVM_DEBUG(dbgs() << "Execute returned:\n");
4682 while (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe.get())) {
4683 LLVM_DEBUG(dbgs() << buffer.data());
4684 llvm::StringRef trimmed = buffer.data();
4685 outputs.push_back(trimmed.trim().str());
4686 }
4687
4688#undef DEBUG_TYPE
4689
4690 return true;
4691}
4692
4693InterpRef CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
4694 const std::vector<const char*>& GpuArgs /*={}*/) {
4695 INTEROP_TRACE(Args, GpuArgs);
4696 // cling keeps the raw argv pointers for its whole lifetime (e.g. in
4697 // CompilerOptions::Remaining), so the strings must outlive it: keep owned
4698 // copies and move them into the interpreter's InterpreterInfo entry.
4699 std::vector<std::string> ArgvStorage;
4700 ArgvStorage.push_back(sys::fs::getMainExecutable(nullptr, nullptr));
4701 // In some systems, CppInterOp cannot manually detect the correct resource.
4702 // Then the -resource-dir passed by the user is assumed to be the correct
4703 // location. Prioritising it over detecting it within CppInterOp. Extracting
4704 // the resource-dir from the arguments is required because we set the
4705 // necessary library search location explicitly below. Because by default,
4706 // linker flags are ignored in repl (issue #748)
4707 std::string ResourceDir = ExtractArgument(Args, "-resource-dir");
4708 if (ResourceDir.empty())
4709 ResourceDir = MakeResourcesPath();
4710 llvm::Triple T(llvm::sys::getProcessTriple());
4711 if ((!sys::fs::is_directory(ResourceDir)) &&
4712 (T.isOSDarwin() || T.isOSLinux()))
4713 ResourceDir = DetectResourceDir();
4714
4715 if (!ResourceDir.empty()) {
4716 ArgvStorage.push_back("-resource-dir");
4717 ArgvStorage.push_back(ResourceDir);
4718 }
4719 ArgvStorage.push_back("-std=c++14");
4720#ifdef _WIN32
4721 // FIXME : Workaround Sema::PushDeclContext assert on windows
4722 ArgvStorage.push_back("-fno-delayed-template-parsing");
4723#endif
4724#if __has_feature(memory_sanitizer)
4725 // Match the host stdlib (msan setup is libc++ end to end; the
4726 // in-process clang otherwise defaults to libstdc++ on Linux and
4727 // JIT'd `std::__cxx11::*` won't resolve against the host's
4728 // `std::__1::*`). User Args appended below can override.
4729 ArgvStorage.push_back("-stdlib=libc++");
4730 // -stdlib=libc++ alone misses <install>/include/c++/v1: in-process
4731 // clang derives Driver::Dir from /proc/self/exe (= host binary),
4732 // not argv[0], so the force-include of `<new>` SIGSEGVs in
4733 // GenModule. Derive the include from -resource-dir, which IS the
4734 // cell. Gating on memory_sanitizer (not _LIBCPP_VERSION) keeps
4735 // this away from generic libc++ builds where the cell-derived
4736 // path may not be the libc++ the host actually uses.
4737 if (!ResourceDir.empty()) {
4738 SmallString<256> P(ResourceDir);
4739 sys::path::remove_filename(P);
4740 sys::path::remove_filename(P);
4741 sys::path::remove_filename(P);
4742 sys::path::append(P, "include", "c++", "v1");
4743 if (sys::fs::is_directory(P)) {
4744 ArgvStorage.push_back("-cxx-isystem");
4745 ArgvStorage.push_back(P.str().str());
4746 }
4747 }
4748#endif
4749 ArgvStorage.insert(ArgvStorage.end(), Args.begin(), Args.end());
4750 // To keep the Interpreter creation interface between cling and clang-repl
4751 // to some extent compatible we should put Args and GpuArgs together. On the
4752 // receiving end we should check for -xcuda to know.
4753 if (!GpuArgs.empty()) {
4754 llvm::StringRef Arg0 = GpuArgs[0];
4755 Arg0 = Arg0.trim().ltrim('-');
4756 if (Arg0 != "cuda") {
4757 llvm::errs() << "[CreateInterpreter]: Make sure --cuda is passed as the"
4758 << " first argument of the GpuArgs\n";
4759 return INTEROP_RETURN(nullptr);
4760 }
4761 }
4762 ArgvStorage.insert(ArgvStorage.end(), GpuArgs.begin(), GpuArgs.end());
4763
4764 // Process externally passed arguments if present.
4765 auto EnvOpt = llvm::sys::Process::GetEnv("CPPINTEROP_EXTRA_INTERPRETER_ARGS");
4766 if (EnvOpt) {
4767 StringRef Env(*EnvOpt);
4768 while (!Env.empty()) {
4769 StringRef Arg;
4770 std::tie(Arg, Env) = Env.split(' ');
4771 ArgvStorage.push_back(Arg.str());
4772 }
4773 }
4774
4775 std::vector<const char*> ClingArgv;
4776 ClingArgv.reserve(ArgvStorage.size());
4777 for (const std::string& Arg : ArgvStorage)
4778 ClingArgv.push_back(Arg.c_str());
4779
4780 // Figure out the right SDK path for MacOS. Mirrors the clang driver's
4781 // resolution (Darwin::AddDeploymentTarget): try an explicit -isysroot,
4782 // else a valid SDKROOT. Only when neither is usable fall back to
4783 // `xcrun --show-sdk-path` (same query xcrun performs to set SDKROOT)
4784 // This way a packaged (pip/conda) interpreter finds the active
4785 // with no env config, relocatably across Xcode updates.
4786 std::string MacOSSDK;
4787 if (T.isOSDarwin()) {
4788 const bool HasSysroot = llvm::any_of(ClingArgv, [](const char* A) {
4789 return llvm::StringRef(A) == "-isysroot";
4790 });
4791 auto SDKRootEnv = llvm::sys::Process::GetEnv("SDKROOT");
4792 const bool ValidSDKRoot = SDKRootEnv &&
4793 llvm::sys::path::is_absolute(*SDKRootEnv) &&
4794 llvm::sys::fs::exists(*SDKRootEnv) &&
4795 llvm::StringRef(*SDKRootEnv) != "/";
4796 if (!HasSysroot && !ValidSDKRoot) {
4797 std::vector<std::string> Out;
4798 if (exec("xcrun --sdk macosx --show-sdk-path", Out) && !Out.empty())
4799 MacOSSDK = Out.back();
4800 if (!MacOSSDK.empty() && llvm::sys::fs::is_directory(MacOSSDK)) {
4801 ClingArgv.push_back("-isysroot");
4802 ClingArgv.push_back(MacOSSDK.c_str());
4803 }
4804 }
4805 }
4806
4807 // Force global process initialization.
4808 (void)GetInterpreters();
4809
4810#ifdef CPPINTEROP_USE_CLING
4811 auto I = new compat::Interpreter(ClingArgv.size(), &ClingArgv[0]);
4812#else
4813 auto Interp =
4814 compat::Interpreter::create(static_cast<int>(ClingArgv.size()),
4815 ClingArgv.data(), nullptr, {}, nullptr, true);
4816 if (!Interp)
4817 return INTEROP_RETURN(nullptr);
4818 auto* I = Interp.release();
4819#endif
4820
4821 // Honor -mllvm.
4822 //
4823 // FIXME: Remove this, one day.
4824 // This should happen AFTER plugins have been loaded!
4825 const CompilerInstance* Clang = I->getCI();
4826 if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
4827 unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
4828 auto Args = std::make_unique<const char*[]>(NumArgs + 2);
4829 Args[0] = "clang (LLVM option parsing)";
4830 for (unsigned i = 0; i != NumArgs; ++i)
4831 Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
4832 Args[NumArgs + 1] = nullptr;
4833 llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
4834 }
4835
4836 if (!T.isWasm())
4837 AddLibrarySearchPaths(ResourceDir, I);
4838
4839 if (GetLanguage(I) != InterpreterLanguage::C) {
4840 I->declare(R"(
4841 namespace __internal_CppInterOp {
4842 template <typename Signature>
4843 struct function;
4844 template <typename Res, typename... ArgTypes>
4845 struct function<Res(ArgTypes...)> {
4846 typedef Res result_type;
4847 };
4848 } // namespace __internal_CppInterOp
4849 )");
4850 }
4851
4852 RegisterInterpreter(I, /*Owned=*/true, std::move(ArgvStorage));
4853
4854// Define runtime symbols in the JIT dylib for clang-repl
4855#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
4856 DefineAbsoluteSymbol(*I, "__ci_newtag",
4857 reinterpret_cast<uint64_t>(&__ci_newtag));
4858// llvm >= 21 has this defined as a C symbol that does not require mangling
4859#if CLANG_VERSION_MAJOR >= 21
4860 DefineAbsoluteSymbol(
4861 *I, "__clang_Interpreter_SetValueWithAlloc",
4862 reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueWithAlloc));
4863#else
4864 // obtain mangled name
4865 auto* D =
4866 unwrap<Decl>(Cpp::GetNamed("__clang_Interpreter_SetValueWithAlloc"));
4867 if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
4868 auto GD = GlobalDecl(FD);
4869 std::string mangledName;
4870 compat::maybeMangleDeclName(GD, mangledName);
4871 DefineAbsoluteSymbol(
4872 *I, mangledName.c_str(),
4873 reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueWithAlloc));
4874 }
4875#endif
4876
4877 DefineAbsoluteSymbol(
4878 *I, "__clang_Interpreter_SetValueNoAlloc",
4879 reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueNoAlloc));
4880#endif
4881 return INTEROP_RETURN(I);
4882}
4883
4884InterpreterLanguage GetLanguage(InterpRef I /*=nullptr*/) {
4885 INTEROP_TRACE(I);
4886 compat::Interpreter* interp = &getInterp(I);
4887 const auto& LO = interp->getCI()->getLangOpts();
4888
4889 // CUDA and HIP reuse C++ language standards, so LangStd alone reports CXX.
4890 if (LO.CUDA)
4891 return INTEROP_RETURN(InterpreterLanguage::CUDA);
4892 if (LO.HIP)
4893 return INTEROP_RETURN(InterpreterLanguage::HIP);
4894
4895 auto standard = clang::LangStandard::getLangStandardForKind(LO.LangStd);
4896 auto lang = static_cast<InterpreterLanguage>(standard.getLanguage());
4897 assert(lang != InterpreterLanguage::Unknown && "Unknown language");
4898 assert(static_cast<unsigned char>(lang) <=
4899 static_cast<unsigned char>(InterpreterLanguage::HLSL) &&
4900 "Unhandled Language");
4901 return INTEROP_RETURN(lang);
4902}
4903
4904InterpreterLanguageStandard GetLanguageStandard(InterpRef I /*=nullptr*/) {
4905 INTEROP_TRACE(I);
4906 compat::Interpreter* interp = &getInterp(I);
4907 const auto& LO = interp->getCI()->getLangOpts();
4908 auto langStandard = static_cast<InterpreterLanguageStandard>(LO.LangStd);
4909 assert(langStandard != InterpreterLanguageStandard::lang_unspecified &&
4910 "Unspecified language standard");
4911 assert(static_cast<unsigned char>(langStandard) <=
4912 static_cast<unsigned char>(
4913 InterpreterLanguageStandard::lang_unspecified) &&
4914 "Unhandled language standard.");
4915 return INTEROP_RETURN(langStandard);
4916}
4917
4918void AddSearchPath(const char* dir, bool isUser, bool prepend) {
4919 INTEROP_TRACE(dir, isUser, prepend);
4920 getInterp().getDynamicLibraryManager()->addSearchPath(dir, isUser, prepend);
4921 return INTEROP_VOID_RETURN();
4922}
4923
4924const char* GetResourceDir() {
4925 INTEROP_TRACE();
4926 return INTEROP_RETURN(
4927 getInterp().getCI()->getHeaderSearchOpts().ResourceDir.c_str());
4928}
4929
4930std::string DetectResourceDir(const char* ClangBinaryName /* = clang */) {
4931 INTEROP_TRACE(ClangBinaryName);
4932 std::string cmd = std::string(ClangBinaryName) + " -print-resource-dir";
4933 std::vector<std::string> outs;
4934 exec(cmd.c_str(), outs);
4935 if (outs.empty() || outs.size() > 1)
4936 return INTEROP_RETURN("");
4937
4938 std::string detected_resource_dir = outs.back();
4939
4940 std::string version = CLANG_VERSION_MAJOR_STRING;
4941 // We need to check if the detected resource directory is compatible.
4942 if (llvm::sys::path::filename(detected_resource_dir) != version)
4943 return INTEROP_RETURN("");
4944
4945 return INTEROP_RETURN(detected_resource_dir);
4946}
4947
4948void DetectSystemCompilerIncludePaths(std::vector<std::string>& Paths,
4949 const char* CompilerName /*= "c++"*/) {
4950 INTEROP_TRACE(INTEROP_OUT(Paths), CompilerName);
4951 std::string cmd = "LC_ALL=C ";
4952 cmd += CompilerName;
4953 cmd += " -xc++ -E -v /dev/null 2>&1 | sed -n -e '/^.include/,${' -e '/^ "
4954 "\\/.*/p' -e '}'";
4955 std::vector<std::string> outs;
4956 exec(cmd.c_str(), Paths);
4957 return INTEROP_VOID_RETURN();
4958}
4959
4960void AddIncludePath(const char* dir) {
4961 INTEROP_TRACE(dir);
4963 return INTEROP_VOID_RETURN();
4964}
4965
4966void GetIncludePaths(std::vector<std::string>& IncludePaths, bool withSystem,
4967 bool withFlags) {
4968 INTEROP_TRACE(INTEROP_OUT(IncludePaths), withSystem, withFlags);
4969 llvm::SmallVector<std::string> paths(1);
4970 getInterp().GetIncludePaths(paths, withSystem, withFlags);
4971 for (auto& i : paths)
4972 IncludePaths.push_back(i);
4973 return INTEROP_VOID_RETURN();
4974}
4975
4976namespace {
4977class clangSilent {
4978public:
4979 clangSilent(clang::DiagnosticsEngine& diag) : fDiagEngine(diag) {
4980 fOldDiagValue = fDiagEngine.getSuppressAllDiagnostics();
4981 fDiagEngine.setSuppressAllDiagnostics(true);
4982 }
4983
4984 ~clangSilent() { fDiagEngine.setSuppressAllDiagnostics(fOldDiagValue); }
4985
4986protected:
4987 clang::DiagnosticsEngine& fDiagEngine;
4989};
4990} // namespace
4991
4992int Declare(compat::Interpreter& I, const char* code, bool silent) {
4993 // Trap diagnostics on both paths: I.declare's rc is 0 even when
4994 // Parse recovered from emitted errors, so callers need the trap to
4995 // distinguish "parsed cleanly" from "parsed with errors".
4996 clang::DiagnosticsEngine& Diag = I.getSema().getDiagnostics();
4997 clang::DiagnosticErrorTrap Trap(Diag);
4998 if (silent) {
4999 clangSilent diagSuppr(Diag);
5000 auto result = I.declare(code);
5001 if (Trap.hasErrorOccurred())
5002 return 1;
5003 return result;
5004 }
5005 auto result = I.declare(code);
5006 if (Trap.hasErrorOccurred())
5007 return 1;
5008 return result;
5009}
5010
5011int Declare(const char* code, bool silent) {
5012 INTEROP_TRACE(code, silent);
5013 return INTEROP_RETURN(Declare(getInterp(), code, silent));
5014}
5015
5016int Process(const char* code) {
5017 INTEROP_TRACE(code);
5018 return INTEROP_RETURN(getInterp().process(code));
5019}
5020
5021// Classify the QualType of a successfully-evaluated value into a
5022// Box::Kind. clang::Value's own ctor asserts on builtins the X-macro
5023// doesn't list (`__int128`, `_BitInt`, `_Float16`, ...), so by the time
5024// we get here QT is non-null and BT->getKind() is one of the enumerated
5025// arms. Records, pointers and references fall through to K_PtrOrObj.
5026// See memory/clang_value_wide_types_gap.md for the upstream follow-up
5027// that would broaden Value's coverage.
5028static Cpp::Box::Kind classifyByQualType(clang::QualType QT) {
5029 if (const auto* BT = QT->getAs<clang::BuiltinType>()) {
5030 switch (BT->getKind()) {
5031 case clang::BuiltinType::Bool:
5032 return Cpp::Box::K_Bool;
5033 case clang::BuiltinType::Char_S:
5034 return Cpp::Box::K_Char_S;
5035 case clang::BuiltinType::Char_U:
5036 // Platform-`unsigned`-char alias; share UChar storage so the
5037 // X-macro doesn't need a duplicate Box::Create<T> specialization.
5038 return Cpp::Box::K_UChar;
5039 case clang::BuiltinType::SChar:
5040 return Cpp::Box::K_SChar;
5041 case clang::BuiltinType::UChar:
5042 return Cpp::Box::K_UChar;
5043 case clang::BuiltinType::Short:
5044 return Cpp::Box::K_Short;
5045 case clang::BuiltinType::UShort:
5046 return Cpp::Box::K_UShort;
5047 case clang::BuiltinType::Int:
5048 return Cpp::Box::K_Int;
5049 case clang::BuiltinType::UInt:
5050 return Cpp::Box::K_UInt;
5051 case clang::BuiltinType::Long:
5052 return Cpp::Box::K_Long;
5053 case clang::BuiltinType::ULong:
5054 return Cpp::Box::K_ULong;
5055 case clang::BuiltinType::LongLong:
5056 return Cpp::Box::K_LongLong;
5057 case clang::BuiltinType::ULongLong:
5058 return Cpp::Box::K_ULongLong;
5059 case clang::BuiltinType::Float:
5060 return Cpp::Box::K_Float;
5061 case clang::BuiltinType::Double:
5062 return Cpp::Box::K_Double;
5063 case clang::BuiltinType::LongDouble:
5065 default:
5066 llvm_unreachable(
5067 "clang::Value asserts on builtins outside the X-macro set");
5068 }
5069 }
5070 return Cpp::Box::K_PtrOrObj;
5071}
5072
5073Box Evaluate(const char* code) {
5074 INTEROP_TRACE(code);
5075 compat::Value V;
5076 auto res = getInterp().evaluate(code, V);
5078 if (res != 0 || !V.hasValue())
5079 return INTEROP_RETURN(Box{});
5080
5081 clang::QualType QT = V.getType();
5082 void* qt = QT.getAsOpaquePtr();
5083 switch (classifyByQualType(QT)) {
5084#define X(TyRef, name) \
5085 case Cpp::Box::K_##name: \
5086 return INTEROP_RETURN( \
5087 Cpp::Box::Create<TyRef>(compat::convertTo<TyRef>(V), qt));
5089#undef X
5091 return INTEROP_RETURN(compat::MakeValueBox(V, qt));
5092 case Cpp::Box::K_Char_U:
5093 case Cpp::Box::K_Void:
5095 // classifyByQualType never produces these (Char_U folds to UChar;
5096 // Void/Unspecified can't reach a hasValue=true path).
5097 llvm_unreachable("Box::Kind not produced by classifyByQualType");
5098 }
5099 llvm_unreachable("classifyByQualType returned an unhandled Kind");
5100}
5101
5102std::string LookupLibrary(const char* lib_name) {
5103 INTEROP_TRACE(lib_name);
5104 return INTEROP_RETURN(
5105 getInterp().getDynamicLibraryManager()->lookupLibrary(lib_name));
5106}
5107
5108bool LoadLibrary(const char* lib_stem, bool lookup) {
5109 INTEROP_TRACE(lib_stem, lookup);
5111 getInterp().loadLibrary(lib_stem, lookup);
5112
5114}
5115
5116void UnloadLibrary(const char* lib_stem) {
5117 INTEROP_TRACE(lib_stem);
5119 return INTEROP_VOID_RETURN();
5120}
5121
5122std::string SearchLibrariesForSymbol(const char* mangled_name,
5123 bool search_system /*true*/) {
5124 INTEROP_TRACE(mangled_name, search_system);
5125 auto* DLM = getInterp().getDynamicLibraryManager();
5126 return INTEROP_RETURN(
5127 DLM->searchLibrariesForSymbol(mangled_name, search_system));
5128}
5129
5131 const char* linker_mangled_name,
5132 uint64_t address) {
5133 // FIXME: This approach is problematic since we could replace a symbol
5134 // whose address was already taken by clients.
5135 //
5136 // A safer approach would be to define our symbol replacements early in the
5137 // bootstrap process like:
5138 // auto J = LLJITBuilder().create();
5139 // if (!J)
5140 // return Err;
5141 //
5142 // if (Jupyter) {
5143 // llvm::orc::SymbolMap Overrides;
5144 // Overrides[J->mangleAndIntern("printf")] =
5145 // { ExecutorAddr::fromPtr(&printf), JITSymbolFlags::Exported };
5146 // Overrides[...] =
5147 // { ... };
5148 // if (auto Err =
5149 // J->getProcessSymbolsJITDylib().define(absoluteSymbols(std::move(Overrides)))
5150 // return Err;
5151 // }
5152
5153 // FIXME: If we still want to do symbol replacement we should use the
5154 // ReplacementManager which is available in llvm 18.
5155 using namespace llvm;
5156 using namespace llvm::orc;
5157
5158 auto Symbol = compat::getSymbolAddress(I, linker_mangled_name);
5159 llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I);
5160 llvm::orc::ExecutionSession& ES = Jit.getExecutionSession();
5161 JITDylib& DyLib = *Jit.getProcessSymbolsJITDylib().get();
5162
5163 if (Error Err = Symbol.takeError()) {
5164 logAllUnhandledErrors(std::move(Err), errs(),
5165 "[InsertOrReplaceJitSymbol] error: ");
5166#define DEBUG_TYPE "orc"
5167 LLVM_DEBUG(ES.dump(dbgs()));
5168#undef DEBUG_TYPE
5169 return true;
5170 }
5171
5172 // Nothing to define, we are redefining the same function.
5173 if (*Symbol && *Symbol == address) {
5174 errs() << "[InsertOrReplaceJitSymbol] warning: redefining '"
5175 << linker_mangled_name << "' with the same address\n";
5176 return true;
5177 }
5178
5179 // Let's inject it.
5180 llvm::orc::SymbolMap InjectedSymbols;
5181 auto& DL = compat::getExecutionEngine(I)->getDataLayout();
5182 char GlobalPrefix = DL.getGlobalPrefix();
5183 std::string tmp(linker_mangled_name);
5184 if (GlobalPrefix != '\0') {
5185 tmp = std::string(1, GlobalPrefix) + tmp;
5186 }
5187 auto Name = ES.intern(tmp);
5188 InjectedSymbols[Name] =
5189 ExecutorSymbolDef(ExecutorAddr(address), JITSymbolFlags::Exported);
5190
5191 // We want to replace a symbol with a custom provided one.
5192 if (Symbol && address)
5193 // The symbol be in the DyLib or in-process.
5194 if (auto Err = DyLib.remove({Name})) {
5195 logAllUnhandledErrors(std::move(Err), errs(),
5196 "[InsertOrReplaceJitSymbol] error: ");
5197 return true;
5198 }
5199
5200 if (Error Err = DyLib.define(absoluteSymbols(InjectedSymbols))) {
5201 logAllUnhandledErrors(std::move(Err), errs(),
5202 "[InsertOrReplaceJitSymbol] error: ");
5203 return true;
5204 }
5205
5206 return false;
5207}
5208
5209bool InsertOrReplaceJitSymbol(const char* linker_mangled_name,
5210 uint64_t address) {
5211 INTEROP_TRACE(linker_mangled_name, address);
5212 return INTEROP_RETURN(
5213 InsertOrReplaceJitSymbol(getInterp(), linker_mangled_name, address));
5214}
5215
5216std::string ObjToString(const char* TyRef, void* obj) {
5217 INTEROP_TRACE(TyRef, obj);
5218 return INTEROP_RETURN(getInterp().toString(TyRef, obj));
5219}
5220
5221static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
5222 TemplateArgumentListInfo& TLI, Sema& S,
5223 bool instantiate_body) {
5224 // This is not right but we don't have a lot of options to choose from as a
5225 // template instantiation requires a valid source location.
5226 SourceLocation fakeLoc = GetValidSLoc(S);
5227 if (auto* FunctionTemplate = dyn_cast<FunctionTemplateDecl>(TemplateD)) {
5228 FunctionDecl* Specialization = nullptr;
5229 clang::sema::TemplateDeductionInfo Info(fakeLoc);
5230 TemplateDeductionResult Result =
5231 S.DeduceTemplateArguments(FunctionTemplate, &TLI, Specialization, Info,
5232 /*IsAddressOfFunction*/ true);
5233 if (Result != TemplateDeductionResult::Success) {
5234 // FIXME: Diagnose what happened.
5235 (void)Result;
5236 }
5237 if (instantiate_body)
5238 InstantiateFunctionDefinition(Specialization);
5239 return Specialization;
5240 }
5241
5242 if (auto* VarTemplate = dyn_cast<VarTemplateDecl>(TemplateD)) {
5243#if CLANG_VERSION_MAJOR < 22
5244 DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI);
5245#else
5246 DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI,
5247 /*SetWrittenArgs=*/true);
5248#endif
5249 if (R.isInvalid()) {
5250 // FIXME: Diagnose
5251 }
5252 return R.get();
5253 }
5254
5255 // This will instantiate tape<T> TyRef and return it.
5256 SourceLocation noLoc;
5257#if CLANG_VERSION_MAJOR < 22
5258 QualType TT = S.CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI);
5259#else
5260 QualType TT = S.CheckTemplateIdType(
5261 ElaboratedTypeKeyword::None, TemplateName(TemplateD), noLoc, TLI,
5262 /*Scope=*/nullptr, /*ForNestedNameSpecifier=*/false);
5263#endif
5264 if (TT.isNull())
5265 return nullptr;
5266
5267 // Perhaps we can extract this into a new interface.
5268 S.RequireCompleteType(fakeLoc, TT, diag::err_tentative_def_incomplete_type);
5269 return GetScopeFromType(TT);
5270
5271 // ASTContext &C = S.getASTContext();
5272 // // Get clad namespace and its identifier clad::.
5273 // CXXScopeSpec CSS;
5274 // CSS.Extend(C, GetCladNamespace(), noLoc, noLoc);
5275 // NestedNameSpecifier* NS = CSS.getScopeRep();
5276
5277 // // Create elaborated TyRef with namespace specifier,
5278 // // i.e. class<T> -> clad::class<T>
5279 // return C.getElaboratedType(ETK_None, NS, TT);
5280}
5281
5282Decl* InstantiateTemplate(TemplateDecl* TemplateD,
5283 ArrayRef<TemplateArgument> TemplateArgs, Sema& S,
5284 bool instantiate_body) {
5285 // Create a list of template arguments.
5286 TemplateArgumentListInfo TLI{};
5287 for (auto TA : TemplateArgs)
5288 TLI.addArgument(
5289 S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));
5290
5291 return InstantiateTemplate(TemplateD, TLI, S, instantiate_body);
5292}
5293
5295 const TemplateArgInfo* template_args,
5296 size_t template_args_size, bool instantiate_body) {
5297 auto& S = I.getSema();
5298 auto& C = S.getASTContext();
5299
5300 llvm::SmallVector<TemplateArgument> TemplateArgs;
5301 TemplateArgs.reserve(template_args_size);
5302 for (size_t i = 0; i < template_args_size; ++i) {
5303 QualType ArgTy = QualType::getFromOpaquePtr(template_args[i].m_Type);
5304 if (template_args[i].m_IntegralValue) {
5305 // We have a non-TyRef template parameter. Create an integral value from
5306 // the string representation.
5307 auto Res = llvm::APSInt(template_args[i].m_IntegralValue);
5308 Res = Res.extOrTrunc(C.getIntWidth(ArgTy));
5309 TemplateArgs.push_back(TemplateArgument(C, Res, ArgTy));
5310 } else {
5311 TemplateArgs.push_back(ArgTy);
5312 }
5313 }
5314
5315 auto* TmplD = unwrap<TemplateDecl>(tmpl);
5316 // We will create a new decl, push a transaction.
5318 return InstantiateTemplate(TmplD, TemplateArgs, S, instantiate_body);
5319}
5320
5321DeclRef InstantiateTemplate(DeclRef tmpl, const TemplateArgInfo* template_args,
5322 size_t template_args_size, bool instantiate_body) {
5323 INTEROP_TRACE(tmpl, template_args, template_args_size, instantiate_body);
5325 getInterp(), tmpl, template_args, template_args_size, instantiate_body));
5326}
5327
5328DeclRef InstantiateTemplate(DeclRef tmpl,
5329 const std::vector<TemplateArgInfo>& template_args,
5330 bool instantiate_body) {
5331 INTEROP_TRACE(tmpl, template_args, instantiate_body);
5332 // Forward to the static helper directly (not the deprecated public
5333 // overload) to avoid a nested INTEROP_TRACE.
5334 return INTEROP_RETURN(
5335 InstantiateTemplate(getInterp(), tmpl, template_args.data(),
5336 template_args.size(), instantiate_body));
5337}
5338
5339void GetClassTemplateArgs(ConstDeclRef templ_instance,
5340 std::vector<TemplateArgInfo>& args) {
5341 INTEROP_TRACE(templ_instance, INTEROP_OUT(args));
5342 const auto* CTSD = unwrap<ClassTemplateSpecializationDecl>(templ_instance);
5343 for (const auto& TA : CTSD->getTemplateArgs().asArray()) {
5344 // FIXME: Support cases with m_IntegralValue.
5345 args.push_back({TA.getAsType().getAsOpaquePtr()});
5346 }
5347 return INTEROP_VOID_RETURN();
5348}
5349
5350void GetClassTemplateInstantiationArgs(ConstDeclRef templ_instance,
5351 std::vector<TemplateArgInfo>& args) {
5352 INTEROP_TRACE(templ_instance, INTEROP_OUT(args));
5353 const auto* CTSD = unwrap<ClassTemplateSpecializationDecl>(templ_instance);
5354 for (const auto& TA : CTSD->getTemplateInstantiationArgs().asArray()) {
5355 switch (TA.getKind()) {
5356 default:
5357 assert(0 && "Not yet supported!");
5358 break;
5359 case TemplateArgument::Pack:
5360 for (auto SubTA : TA.pack_elements())
5361 args.push_back({SubTA.getAsType().getAsOpaquePtr()});
5362 break;
5363 case TemplateArgument::Integral:
5364 // FIXME: Support this case where the problem is where we provide the
5365 // storage for the m_IntegralValue.
5366 // llvm::APSInt Val = TA.getAsIntegral();
5367 // args.push_back({TA.getIntegralType(), TA.getAsIntegral()})
5368 // break;
5369 case TemplateArgument::Type:
5370 args.push_back({TA.getAsType().getAsOpaquePtr()});
5371 }
5372 }
5373 return INTEROP_VOID_RETURN();
5374}
5375
5376FuncRef InstantiateTemplateFunctionFromString(const char* function_template) {
5377 INTEROP_TRACE(function_template);
5378 // FIXME: Drop this interface and replace it with the proper overload
5379 // resolution handling and template instantiation selection.
5380
5381 // Try to force template instantiation and overload resolution.
5382 static unsigned long long var_count = 0;
5383 std::string id = "__Cppyy_GetMethTmpl_" + std::to_string(var_count++);
5384 std::string instance = "auto " + id + " = " + function_template + ";\n";
5385
5386 if (!Cpp::Declare(instance.c_str(), /*silent=*/false)) {
5387 auto* VD = unwrap<VarDecl>(Cpp::GetNamed(id, nullptr));
5388 DeclRefExpr* DRE = (DeclRefExpr*)VD->getInit()->IgnoreImpCasts();
5389 return INTEROP_RETURN(DRE->getDecl());
5390 }
5391 return INTEROP_RETURN(nullptr);
5392}
5393
5394void GetAllCppNames(ConstDeclRef DRef, std::set<std::string>& names) {
5395 INTEROP_TRACE(DRef, INTEROP_OUT(names));
5396 const auto* D = unwrap<clang::Decl>(DRef);
5397 clang::DeclContext* DC;
5398 clang::DeclContext::decl_iterator decl;
5399
5401
5402 if (const auto* TD = dyn_cast_or_null<TagDecl>(D)) {
5403 DC = clang::TagDecl::castToDeclContext(TD);
5404 decl = DC->decls_begin();
5405 decl++;
5406 } else if (const auto* ND = dyn_cast_or_null<NamespaceDecl>(D)) {
5407 DC = clang::NamespaceDecl::castToDeclContext(ND);
5408 decl = DC->decls_begin();
5409 } else if (const auto* TUD = dyn_cast_or_null<TranslationUnitDecl>(D)) {
5410 DC = clang::TranslationUnitDecl::castToDeclContext(TUD);
5411 decl = DC->decls_begin();
5412 } else {
5413 return INTEROP_VOID_RETURN();
5414 }
5415
5416 for (/* decl set above */; decl != DC->decls_end(); decl++) {
5417 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(*decl)) {
5418 names.insert(ND->getNameAsString());
5419 }
5420 }
5421 return INTEROP_VOID_RETURN();
5422}
5423
5424void GetEnums(ConstDeclRef DRef, std::vector<std::string>& Result) {
5425 INTEROP_TRACE(DRef, INTEROP_OUT(Result));
5426 // collectAllContexts is non-const but logically read-only here.
5427 auto* D = const_cast<clang::Decl*>(unwrap<clang::Decl>(DRef));
5428
5429 if (!llvm::isa_and_nonnull<clang::DeclContext>(D))
5430 return INTEROP_VOID_RETURN();
5431
5432 auto* DC = llvm::dyn_cast<clang::DeclContext>(D);
5433
5434 llvm::SmallVector<clang::DeclContext*, 4> DCs;
5435 DC->collectAllContexts(DCs);
5436
5437 // FIXME: We should use a lookup based approach instead of brute force
5438 for (auto* DC : DCs) {
5439 for (auto decl = DC->decls_begin(); decl != DC->decls_end(); decl++) {
5440 if (auto* ND = llvm::dyn_cast_or_null<EnumDecl>(*decl)) {
5441 Result.push_back(ND->getNameAsString());
5442 }
5443 }
5444 }
5445 return INTEROP_VOID_RETURN();
5446}
5447
5448// FIXME: On the CPyCppyy side the receiver is of TyRef
5449// vector<long int> instead of vector<size_t>
5450std::vector<long int> GetDimensions(ConstTypeRef TyRef) {
5451 INTEROP_TRACE(TyRef);
5452 QualType Qual = QualType::getFromOpaquePtr(TyRef.data);
5453 if (Qual.isNull())
5454 return INTEROP_RETURN(std::vector<long int>{});
5455 Qual = Qual.getCanonicalType();
5456 std::vector<long int> dims;
5457 if (Qual->isArrayType()) {
5458 const auto* ArrayType = dyn_cast<clang::ArrayType>(Qual.getTypePtr());
5459 while (ArrayType) {
5460 if (const auto* CAT = dyn_cast_or_null<ConstantArrayType>(ArrayType)) {
5461 llvm::APSInt Size(CAT->getSize());
5462 long int ArraySize = Size.getLimitedValue();
5463 dims.push_back(ArraySize);
5464 } else /* VariableArrayType, DependentSizedArrayType, IncompleteArrayType
5465 */
5466 {
5467 dims.push_back(DimensionValue::UNKNOWN_SIZE);
5468 }
5469 ArrayType = ArrayType->getElementType()->getAsArrayTypeUnsafe();
5470 }
5471 return INTEROP_RETURN(dims);
5472 }
5473 return INTEROP_RETURN(dims);
5474}
5475
5476bool IsTypeDerivedFrom(ConstTypeRef derived, ConstTypeRef base) {
5477 INTEROP_TRACE(derived, base);
5478 auto& S = getSema();
5479 auto fakeLoc = GetValidSLoc(S);
5480 auto derivedType = clang::QualType::getFromOpaquePtr(derived.data);
5481 auto baseType = clang::QualType::getFromOpaquePtr(base.data);
5482
5484 return INTEROP_RETURN(S.IsDerivedFrom(fakeLoc, derivedType, baseType));
5485}
5486
5487std::string GetFunctionArgDefault(ConstFuncRef func, size_t param_index) {
5488 INTEROP_TRACE(func, param_index);
5489 const auto* D = unwrap<clang::Decl>(func);
5490 const clang::ParmVarDecl* PI = nullptr;
5491
5492 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
5493 PI = FD->getNonObjectParameter(param_index);
5494
5495 else if (const auto* FD =
5496 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
5497 PI = (FD->getTemplatedDecl())->getNonObjectParameter(param_index);
5498
5499 if (PI->hasDefaultArg()) {
5500 std::string Result;
5501 llvm::raw_string_ostream OS(Result);
5502 const Expr* DefaultArgExpr = nullptr;
5504 if (PI->hasUninstantiatedDefaultArg())
5505 DefaultArgExpr = PI->getUninstantiatedDefaultArg();
5506 else
5507 DefaultArgExpr = PI->getDefaultArg();
5508 DefaultArgExpr->printPretty(OS, nullptr, PrintingPolicy(LangOptions()));
5509
5510 // FIXME: Floats are printed in clang with the precision of their underlying
5511 // representation and not as written. This is a deficiency in the printing
5512 // mechanism of clang which we require extra work to mitigate. For example
5513 // float PI = 3.14 is printed as 3.1400000000000001
5514 if (PI->getType()->isFloatingType()) {
5515 if (!Result.empty() && Result.back() == '.')
5516 return INTEROP_RETURN(Result);
5517 auto DefaultArgValue = std::stod(Result);
5518 std::ostringstream oss;
5519 oss << DefaultArgValue;
5520 Result = oss.str();
5521 }
5522 return INTEROP_RETURN(Result);
5523 }
5524 return INTEROP_RETURN("");
5525}
5526
5527bool IsConstMethod(ConstFuncRef method) {
5528 INTEROP_TRACE(method);
5529 if (!method)
5530 return INTEROP_RETURN(false);
5531
5532 const auto* D = unwrap<clang::Decl>(method);
5533 if (const auto* func = dyn_cast<CXXMethodDecl>(D))
5534 return INTEROP_RETURN(func->getMethodQualifiers().hasConst());
5535
5536 return INTEROP_RETURN(false);
5537}
5538
5539std::string GetFunctionArgName(ConstFuncRef func, size_t param_index) {
5540 INTEROP_TRACE(func, param_index);
5541 const auto* D = unwrap<clang::Decl>(func);
5542 const clang::ParmVarDecl* PI = nullptr;
5543
5544 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
5545 PI = FD->getNonObjectParameter(param_index);
5546 else if (const auto* FD =
5547 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
5548 PI = (FD->getTemplatedDecl())->getNonObjectParameter(param_index);
5549
5550 return INTEROP_RETURN(PI->getNameAsString());
5551}
5552
5553std::string GetSpellingFromOperator(Operator Operator) {
5554 INTEROP_TRACE(Operator);
5555 return INTEROP_RETURN(
5556 clang::getOperatorSpelling((clang::OverloadedOperatorKind)Operator));
5557}
5558
5559Operator GetOperatorFromSpelling(const std::string& op) {
5560 INTEROP_TRACE(op);
5561#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
5562 if ((Spelling) == op) { \
5563 return INTEROP_RETURN((Operator)OO_##Name); \
5564 }
5565#include "clang/Basic/OperatorKinds.def"
5566 return INTEROP_RETURN(Operator::OP_None);
5567}
5568
5569OperatorArity GetOperatorArity(ConstFuncRef op) {
5570 INTEROP_TRACE(op);
5571 const auto* D = unwrap<Decl>(op);
5572 if (const auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
5573 if (FD->isOverloadedOperator()) {
5574 switch (FD->getOverloadedOperator()) {
5575#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
5576 case OO_##Name: \
5577 if ((Unary) && (Binary)) \
5578 return INTEROP_RETURN(kBoth); \
5579 if (Unary) \
5580 return INTEROP_RETURN(kUnary); \
5581 if (Binary) \
5582 return INTEROP_RETURN(kBinary); \
5583 break;
5584#include "clang/Basic/OperatorKinds.def"
5585 default:
5586 break;
5587 }
5588 }
5589 }
5590 return INTEROP_RETURN((OperatorArity)~0U);
5591}
5592
5593void GetOperator(ConstDeclRef DRef, Operator op,
5594 std::vector<FuncRef>& operators, OperatorArity kind) {
5595 INTEROP_TRACE(DRef, op, INTEROP_OUT(operators), kind);
5596 const auto* D = unwrap<Decl>(DRef);
5598 if (const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
5599 auto fn = [&operators, kind, op](const RecordDecl* RD) {
5600 ASTContext& C = RD->getASTContext();
5601 DeclContextLookupResult Result =
5602 RD->lookup(C.DeclarationNames.getCXXOperatorName(
5603 (clang::OverloadedOperatorKind)op));
5604 for (auto* i : Result) {
5605 if (kind & GetOperatorArity(i))
5606 operators.push_back(i);
5607 }
5608 return true;
5609 };
5610 fn(CXXRD);
5611 CXXRD->forallBases(fn);
5612 } else if (const auto* DC = llvm::dyn_cast_or_null<DeclContext>(D)) {
5613 ASTContext& C = getSema().getASTContext();
5614 DeclContextLookupResult Result =
5615 DC->lookup(C.DeclarationNames.getCXXOperatorName(
5616 (clang::OverloadedOperatorKind)op));
5617
5618 for (auto* i : Result) {
5619 if (kind & GetOperatorArity(i))
5620 operators.push_back(i);
5621 }
5622 }
5623 return INTEROP_VOID_RETURN();
5624}
5625
5626ObjectRef Allocate(DeclRef DRef, size_t count) {
5627 INTEROP_TRACE(DRef, count);
5628 return INTEROP_RETURN((ObjectRef)::operator new(Cpp::SizeOf(DRef) * count));
5629}
5630
5631void Deallocate(DeclRef DRef, ObjectRef address, size_t count) {
5632 INTEROP_TRACE(DRef, address, count);
5633 size_t bytes = Cpp::SizeOf(DRef) * count;
5634 ::operator delete(address.data, bytes);
5635 return INTEROP_VOID_RETURN();
5636}
5637
5638// FIXME: Add optional arguments to the operator new.
5639ObjectRef Construct(compat::Interpreter& interp, DeclRef DRef,
5640 void* arena /*=nullptr*/, size_t count /*=1UL*/) {
5641
5642 // DRef may be either a class or a specific constructor declaration.
5643 FuncRef ctorAsFunc = wrap<FuncRef>(DRef.data);
5644 if (!Cpp::IsConstructor(ctorAsFunc) && !Cpp::IsClass(DRef))
5645 return nullptr;
5646 if (Cpp::IsClass(DRef) && !HasDefaultConstructor(DRef))
5647 return nullptr;
5648
5649 FuncRef ctor = nullptr;
5650 if (Cpp::IsClass(DRef))
5651 ctor = Cpp::GetDefaultConstructor(DRef);
5652 else // a ctor
5653 ctor = ctorAsFunc;
5654
5655 if (JitCall JC = MakeFunctionCallable(&interp, ctor)) {
5656 // invoke the constructor (placement/heap) in one shot
5657 // flag is non-null for placement new, null for normal new
5658 void* is_arena = arena ? reinterpret_cast<void*>(1) : nullptr;
5659 void* result = arena;
5660 JC.InvokeConstructor(&result, count, /*args=*/{}, is_arena);
5661 return result;
5662 }
5663 return nullptr;
5664}
5665
5666ObjectRef Construct(DeclRef DRef, void* arena /*=nullptr*/,
5667 size_t count /*=1UL*/) {
5668 INTEROP_TRACE(DRef, arena, count);
5669 return INTEROP_RETURN(Construct(getInterp(), DRef, arena, count));
5670}
5671
5672bool Destruct(compat::Interpreter& interp, ObjectRef This, const Decl* Class,
5673 bool withFree, size_t nary) {
5674 if (auto wrapper = make_dtor_wrapper(interp, Class)) {
5675 (*wrapper)(This.data, nary, withFree);
5676 return true;
5677 }
5678 return false;
5679 // FIXME: Enable stronger diagnostics
5680}
5681
5682bool Destruct(ObjectRef This, DeclRef DRef, bool withFree /*=true*/,
5683 size_t count /*=0UL*/) {
5684 INTEROP_TRACE(This, DRef, withFree, count);
5685 const auto* Class = unwrap<Decl>(DRef);
5686 return INTEROP_RETURN(Destruct(getInterp(), This, Class, withFree, count));
5687}
5688
5690 FILE* m_TempFile = nullptr;
5691 int m_FD = -1;
5692 int m_DupFD = -1;
5693 bool m_OwnsFile = true;
5694
5695public:
5696#ifdef _MSC_VER
5697 StreamCaptureInfo(int FD)
5698 : m_TempFile{[]() {
5699 FILE* stream = nullptr;
5700 errno_t err;
5701 err = tmpfile_s(&stream);
5702 if (err)
5703 printf("Cannot create temporary file!\n");
5704 return stream;
5705 }()},
5706 m_FD(FD) {
5707#else
5708 StreamCaptureInfo(int FD) : m_FD(FD) {
5709#if !defined(CPPINTEROP_USE_CLING) && !defined(_WIN32)
5710 auto& I = getInterp();
5711 if (I.isOutOfProcess()) {
5712 // Use interpreter-managed redirection file for out-of-process
5713 // redirection. Since, we are using custom pipes instead of stdout, sterr,
5714 // it is kind of necessary to have this complication in StreamCaptureInfo.
5715
5716 // TODO(issues/733): Refactor the stream redirection
5717 FILE* redirected = I.getRedirectionFileForOutOfProcess(FD);
5718 if (redirected) {
5719 m_TempFile = redirected;
5720 m_OwnsFile = false;
5721 if (ftruncate(fileno(m_TempFile), 0) != 0)
5722 perror("ftruncate");
5723 if (lseek(fileno(m_TempFile), 0, SEEK_SET) == -1)
5724 perror("lseek");
5725 }
5726 } else {
5727 m_TempFile = tmpfile();
5728 }
5729#else
5730 m_TempFile = tmpfile();
5731#endif
5732#endif
5733
5734 if (!m_TempFile) {
5735 perror("StreamCaptureInfo: Unable to create temp file");
5736 return;
5737 }
5738
5739 m_DupFD = dup(FD);
5740
5741 // Flush now or can drop the buffer when dup2 is called with Fd later.
5742 // This seems only necessary when piping stdout or stderr, but do it
5743 // for ttys to avoid over complicated code for minimal benefit.
5744 ::fflush(FD == STDOUT_FILENO ? stdout : stderr);
5745 if (dup2(fileno(m_TempFile), FD) < 0)
5746 perror("StreamCaptureInfo:");
5747 }
5752
5754 assert(m_DupFD == -1 && "Captured output not used?");
5755 // Only close the temp file if we own it
5756 if (m_OwnsFile && m_TempFile)
5757 fclose(m_TempFile);
5758 }
5759
5760 std::string GetCapturedString() {
5761 assert(m_DupFD != -1 && "Multiple calls to GetCapturedString");
5762
5763 fflush(nullptr);
5764 if (dup2(m_DupFD, m_FD) < 0)
5765 perror("StreamCaptureInfo:");
5766 // Go to the end of the file.
5767 if (fseek(m_TempFile, 0L, SEEK_END) != 0)
5768 perror("StreamCaptureInfo:");
5769
5770 // Get the size of the file.
5771 long bufsize = ftell(m_TempFile);
5772 if (bufsize == -1) {
5773 perror("StreamCaptureInfo:");
5774 close(m_DupFD);
5775 m_DupFD = -1;
5776 return "";
5777 }
5778
5779 // Allocate our buffer to that size.
5780 std::unique_ptr<char[]> content(new char[bufsize + 1]);
5781
5782 // Go back to the start of the file.
5783 if (fseek(m_TempFile, 0L, SEEK_SET) != 0)
5784 perror("StreamCaptureInfo:");
5785
5786 // Read the entire file into memory.
5787 size_t newLen = fread(content.get(), sizeof(char), bufsize, m_TempFile);
5788 if (ferror(m_TempFile) != 0)
5789 fputs("Error reading file", stderr);
5790 else
5791 content[newLen++] = '\0'; // Just to be safe.
5792
5793 std::string result = content.get();
5794 close(m_DupFD);
5795 m_DupFD = -1;
5796#if !defined(_WIN32) && !defined(CPPINTEROP_USE_CLING)
5797 auto& I = getInterp();
5798 if (I.isOutOfProcess()) {
5799 int fd = fileno(m_TempFile);
5800 if (ftruncate(fd, 0) != 0)
5801 perror("ftruncate");
5802 if (lseek(fd, 0, SEEK_SET) == -1)
5803 perror("lseek");
5804 }
5805#endif
5806 return result;
5807 }
5808};
5809
5810static std::stack<StreamCaptureInfo>& GetRedirectionStack() {
5811 static std::stack<StreamCaptureInfo> sRedirectionStack;
5812 return sRedirectionStack;
5813}
5814
5815void BeginStdStreamCapture(CaptureStreamKind fd_kind) {
5816 INTEROP_TRACE(fd_kind);
5817 GetRedirectionStack().emplace((int)fd_kind);
5818 return INTEROP_VOID_RETURN();
5819}
5820
5821std::string EndStdStreamCapture() {
5822 INTEROP_TRACE();
5823 assert(GetRedirectionStack().size());
5825 std::string result = SCI.GetCapturedString();
5826 GetRedirectionStack().pop();
5827 return INTEROP_RETURN(result);
5828}
5829
5830void CodeComplete(std::vector<std::string>& Results, const char* code,
5831 unsigned complete_line /* = 1U */,
5832 unsigned complete_column /* = 1U */) {
5833 INTEROP_TRACE(INTEROP_OUT(Results), code, complete_line, complete_column);
5834 compat::codeComplete(Results, getInterp(), code, complete_line,
5835 complete_column);
5836 return INTEROP_VOID_RETURN();
5837}
5838
5839int Undo(unsigned N) {
5840 INTEROP_TRACE(N);
5842#ifdef CPPINTEROP_USE_CLING
5843 getInterp().unload(N);
5845#else
5846 return INTEROP_RETURN(getInterp().undo(N));
5847#endif
5848}
5849
5850} // namespace Cpp
#define CPP_BOX_BUILTIN_TYPES
Definition Box.h:79
#define clang_LookupResult_Found_Overloaded
#define clang_LookupResult_Not_Found
#define clang_LookupResult_Found
#define CPPINTEROP_API
bool fOldDiagValue
struct __clang_Interpreter_NewTag __ci_newtag
std::unordered_map< const clang::FunctionDecl *, std::optional< AllocType > > & visitedFuncs
#define CPPINTEROP_MSAN_UNPOISON_VALUE(v)
clang::DiagnosticsEngine & fDiagEngine
void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,...)
std::optional< AllocType > result
std::unordered_map< const clang::VarDecl *, std::optional< AllocType > > varMap
void * __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal, void *OpaqueType)
#define ACCESS(OBJECT, MEMBER)
Definition Sins.h:21
#define ALLOW_ACCESS(CLASS, MEMBER,...)
Definition Sins.h:9
#define INTEROP_TRACE(...)
Definition Tracing.h:853
#define INTEROP_RETURN(Val)
Definition Tracing.h:858
#define INTEROP_VOID_RETURN()
Definition Tracing.h:859
#define INTEROP_OUT(Var)
Definition Tracing.h:861
std::string writeToFile(const std::string &Version="")
Write the accumulated reproducer log to a file.
Definition Tracing.cpp:196
void unloadLibrary(llvm::StringRef libStem)
void addSearchPath(llvm::StringRef dir, bool isUser=true, bool prepend=false)
CppInterOp Interpreter.
llvm::Expected< clang::PartialTranslationUnit & > Parse(llvm::StringRef Code)
CompilationResult declare(const std::string &input, clang::PartialTranslationUnit **PTU=nullptr)
CompilationResult loadLibrary(const std::string &filename, bool lookup)
llvm::Error Execute(clang::PartialTranslationUnit &T)
static std::unique_ptr< Interpreter > create(int argc, const char *const *argv, const char *llvmdir=nullptr, const std::vector< std::shared_ptr< clang::ModuleFileExtension > > &moduleExtensions={}, void *extraLibHandle=nullptr, bool noRuntime=true)
const DynamicLibraryManager * getDynamicLibraryManager() const
void AddIncludePath(llvm::StringRef PathsStr)
Adds a single include path (-I).
const clang::CompilerInstance * getCI() const
void * getAddressOfGlobal(const clang::GlobalDecl &GD) const
CompilationResult
Describes the return result of the different routines that do the incremental compilation.
CompilationResult evaluate(const std::string &input, clang::Value &V)
clang::Sema & getSema() const
void GetIncludePaths(llvm::SmallVectorImpl< std::string > &incpaths, bool withSystem, bool withFlags) const
Get the current include paths that are used.
void * compileFunction(llvm::StringRef name, llvm::StringRef code, bool ifUnique, bool withAccessControl)
Definition Box.h:96
Kind
Definition Box.h:99
@ K_PtrOrObj
Definition Box.h:105
@ K_Char_S
Definition Box.h:101
@ K_Double
Definition Box.h:101
@ K_LongLong
Definition Box.h:101
@ K_Char_U
Definition Box.h:103
@ K_Short
Definition Box.h:101
@ K_Long
Definition Box.h:101
@ K_SChar
Definition Box.h:101
@ K_Unspecified
Definition Box.h:106
@ K_UInt
Definition Box.h:101
@ K_Int
Definition Box.h:101
@ K_LongDouble
Definition Box.h:101
@ K_Float
Definition Box.h:101
@ K_Bool
Definition Box.h:101
@ K_ULongLong
Definition Box.h:101
@ K_UShort
Definition Box.h:101
@ K_UChar
Definition Box.h:101
@ K_ULong
Definition Box.h:101
@ K_Void
Definition Box.h:104
StreamCaptureInfo(const StreamCaptureInfo &)=delete
StreamCaptureInfo & operator=(const StreamCaptureInfo &)=delete
StreamCaptureInfo & operator=(StreamCaptureInfo &&)=delete
std::string GetCapturedString()
StreamCaptureInfo(StreamCaptureInfo &&)=delete
void InitTracing()
Activate tracing.
Definition Tracing.cpp:48
TraceInfo * TheTraceInfo
Process-global tracer pointer.
Definition Tracing.cpp:46
void Named(clang::Sema *S, clang::LookupResult &R, const clang::DeclContext *Within=nullptr)
static constexpr int kVTableOverlayPrefixSize
Definition CppInterOp.h:51
Definition Box.h:70
bool IsPODType(ConstTypeRef TyRef)
void BeginStdStreamCapture(CaptureStreamKind fd_kind)
bool IsSameType(ConstTypeRef type_a, ConstTypeRef type_b)
DeclRef GetUnderlyingScope(ConstDeclRef DRef)
bool DeleteInterpreter(InterpRef I)
void GetEnums(ConstDeclRef DRef, std::vector< std::string > &Result)
void InstallDiagConsumer(InterpreterInfo *II)
Wire CppInterOp's DiagnosticConsumer into the interpreter's DiagnosticsEngine so parser/sema diagnost...
TypeRef GetCanonicalType(ConstTypeRef TyRef)
static bool isSmartPointer(const RecordType *RT)
bool IsComplete(ConstDeclRef DRef)
void UseExternalInterpreter(InterpRef I)
InterpreterLanguageStandard GetLanguageStandard(InterpRef I)
std::vector< FuncRef > GetFunctionsUsingName(ConstDeclRef DRef, const std::string &name)
void CppInterOpTraceJitCallInvokeImpl(const JitCall *JC, void *result, void **args, std::size_t nargs, void *self)
std::string GetTypeAsString(ConstTypeRef var)
bool IsProtectedMethod(ConstFuncRef method)
DeclRef GetScope(const std::string &name, ConstDeclRef parent)
TypeRef RemoveTypeQualifier(ConstTypeRef TyRef, QualKind qual)
static Decl * GetScopeFromType(QualType QT)
int64_t GetBaseClassOffset(ConstDeclRef derived, ConstDeclRef base)
void GetAllCppNames(ConstDeclRef DRef, std::set< std::string > &names)
bool IsRecordType(ConstTypeRef TyRef)
static VTableOverlay * applyVTableOverlay(void *inst, int total_method_slots, const int *slots, void *const *fns, std::size_t n, std::size_t n_extra_prefix_slots)
bool CheckVariableAccess(ConstDeclRef var, AccessSpecifier AS)
ValueKind GetValueKind(ConstTypeRef TyRef)
std::string GetFunctionArgDefault(ConstFuncRef func, size_t param_index)
std::string ObjToString(const char *TyRef, void *obj)
Operator GetOperatorFromSpelling(const std::string &op)
TypeRef GetTypeFromScope(ConstDeclRef DRef)
std::vector< DeclRef > GetEnumConstants(ConstDeclRef DRef)
bool IsVoidPointerType(ConstTypeRef TyRef)
FuncRef GetDestructor(ConstDeclRef DRef)
int Undo(unsigned N)
InterpreterInfo * GetInterpInfo(InterpRef I)
Resolve an InterpRef to the impl-side struct.
bool IsDestructor(ConstFuncRef method)
std::string GetSpellingFromOperator(Operator Operator)
TypeRef GetIntegerTypeFromEnumType(ConstTypeRef enum_type)
bool IsEnumType(ConstTypeRef TyRef)
FuncRef InstantiateTemplateFunctionFromString(const char *function_template)
bool IsLambdaClass(ConstTypeRef TyRef)
static std::optional< AllocType > AnalyzeAllocType(const clang::FunctionDecl *Fn, std::unordered_map< const clang::FunctionDecl *, std::optional< AllocType > > &visitedFuncs)
void DetectSystemCompilerIncludePaths(std::vector< std::string > &Paths, const char *CompilerName)
bool IsAllocator(ConstFuncRef Fn)
DeclRef GetParentScope(ConstDeclRef DRef)
bool HasTypeQualifier(ConstTypeRef TyRef, QualKind qual)
std::vector< DeclRef > GetUsingNamespaces(ConstDeclRef DRef)
TypeRef GetPointeeType(ConstTypeRef TyRef)
InterpRef CreateInterpreter(const std::vector< const char * > &Args, const std::vector< const char * > &GpuArgs)
void CodeComplete(std::vector< std::string > &Results, const char *code, unsigned complete_line, unsigned complete_column)
size_t GetFunctionRequiredArgs(ConstFuncRef func)
DeclRef GetScopeFromCompleteName(const std::string &name)
std::string GetQualifiedName(ConstDeclRef DRef)
bool IsPrivateVariable(ConstDeclRef var)
ObjectRef Construct(compat::Interpreter &interp, DeclRef DRef, void *arena, size_t count)
bool IsTemplateSpecialization(ConstDeclRef DRef)
bool ActivateInterpreter(InterpRef I)
bool IsEnumConstant(ConstDeclRef DRef)
bool InsertOrReplaceJitSymbol(compat::Interpreter &I, const char *linker_mangled_name, uint64_t address)
bool Destruct(compat::Interpreter &interp, ObjectRef This, const Decl *Class, bool withFree, size_t nary)
OperatorArity GetOperatorArity(ConstFuncRef op)
bool IsVariable(ConstDeclRef DRef)
bool HasDefaultConstructor(ConstDeclRef DRef)
size_t GetSizeOfType(ConstTypeRef TyRef)
bool IsConstructor(ConstFuncRef method)
std::string Demangle(const std::string &mangled_name)
TypeRef GetFunctionReturnType(ConstFuncRef func)
void GetIncludePaths(std::vector< std::string > &IncludePaths, bool withSystem, bool withFlags)
size_t SizeOf(ConstDeclRef DRef)
static Decl * InstantiateTemplate(TemplateDecl *TemplateD, TemplateArgumentListInfo &TLI, Sema &S, bool instantiate_body)
bool ExistsFunctionTemplate(const std::string &name, ConstDeclRef parent)
constexpr int kMinVTableMethodSlots
void EnableDebugOutput(bool value)
std::string EndStdStreamCapture()
bool GetClassTemplatedMethods(const std::string &name, ConstDeclRef parent, std::vector< FuncRef > &funcs)
static QualType findBuiltinType(llvm::StringRef typeName, ASTContext &Context)
Box Evaluate(const char *code)
void AddIncludePath(const char *dir)
static void GetClassDecls(ConstDeclRef DRef, std::vector< HandleType > &methods)
bool IsVirtualMethod(ConstFuncRef method)
constexpr int kABIPrefixSize
std::string DetectResourceDir(const char *ClangBinaryName)
static void RegisterPerms(llvm::StringMap< QualType > &Map, QualType QT, llvm::SmallVectorImpl< llvm::StringRef > &Words)
bool IsStaticVariable(ConstDeclRef var)
std::string GetFunctionSignature(ConstFuncRef func)
const char * GetResourceDir()
bool IsPublicVariable(ConstDeclRef var)
TypeRef AddTypeQualifier(ConstTypeRef TyRef, QualKind qual)
void * GetFunctionAddress(const char *mangled_name)
DeclRef GetNamed(const std::string &name, ConstDeclRef parent)
static DeclarationName getCXXOperatorDeclName(ASTContext &Ctx, llvm::StringRef name)
static InterpreterInfo & getInterpInfo(compat::Interpreter *I=nullptr)
std::string GetName(ConstDeclRef DRef)
void DestroyVTableOverlay(VTableOverlay *overlay)
static void DefaultProcessCrashHandler(void *)
constexpr int kDeletingDtorSlot
void GetClassTemplateArgs(ConstDeclRef templ_instance, std::vector< TemplateArgInfo > &args)
std::string GetCompleteName(ConstDeclRef DRef)
TypeRef GetVariableType(ConstDeclRef var)
std::string GetDoxygenComment(ConstDeclRef DRef, bool strip_comment_markers)
bool IsReferenceType(ConstTypeRef TyRef)
static void ForceCodeGen(Decl *D, compat::Interpreter &I)
static std::deque< InterpreterInfo > & GetInterpreters(bool SetCrashHandler=true)
TypeRef GetEnumConstantType(ConstDeclRef DRef)
DeclRef GetBaseClass(ConstDeclRef DRef, size_t ibase)
static void InstantiateFunctionDefinition(Decl *D)
bool IsFunction(ConstDeclRef DRef)
bool IsConstMethod(ConstFuncRef method)
TypeRef GetNonReferenceType(ConstTypeRef TyRef)
DeclRef LookupDatamember(const std::string &name, ConstDeclRef parent)
static bool exec(const char *cmd, std::vector< std::string > &outputs)
std::string GetFunctionArgName(ConstFuncRef func, size_t param_index)
int Declare(compat::Interpreter &I, const char *code, bool silent)
void UnloadLibrary(const char *lib_stem)
bool IsStaticMethod(ConstFuncRef method)
void Deallocate(DeclRef DRef, ObjectRef address, size_t count)
bool IsNamespace(ConstDeclRef DRef)
static VTableOverlayDtorSlotFn SlotToDtorFn(void *slot)
InterpreterLanguage GetLanguage(InterpRef I)
bool IsTemplatedFunction(ConstFuncRef func)
bool IsClassPolymorphic(ConstDeclRef DRef)
void GetClassTemplateInstantiationArgs(ConstDeclRef templ_instance, std::vector< TemplateArgInfo > &args)
bool IsDeallocator(ConstFuncRef Fn)
static const clang::Decl * GetUnderlyingScopeImpl(const clang::Decl *D)
static std::optional< QualType > GetTypeInternal(const Decl *D)
bool CheckMethodAccess(ConstFuncRef method, AccessSpecifier AS)
void GetClassMethods(ConstDeclRef DRef, std::vector< FuncRef > &methods)
bool IsFunctionDeleted(ConstFuncRef function)
static clang::Sema & getSema()
bool IsTemplate(ConstDeclRef DRef)
void DumpScope(ConstDeclRef DRef)
TypeRef GetComplexType(ConstTypeRef TyRef)
void CppInterOpTraceJitCallInvokeReturnImpl(const JitCall *JC, void *result)
bool IsPrivateMethod(ConstFuncRef method)
std::string GetBuildInfo()
static int virtualMethodSlot(ConstFuncRef method)
static bool hasComplexVTableLayout(const CXXRecordDecl *RD)
TypeRef GetIntegerTypeFromEnumScope(ConstDeclRef DRef)
static Cpp::Box::Kind classifyByQualType(clang::QualType QT)
static clang::ASTContext & getASTContext()
bool IsEnumScope(ConstDeclRef DRef)
TypeRef GetType(const std::string &name, ConstDeclRef parent)
bool IsTemplateParmType(ConstTypeRef TyRef)
JitCall MakeFunctionCallable(InterpRef I, ConstFuncRef func)
bool IsMethod(ConstFuncRef method)
static SourceLocation GetValidSLoc(Sema &semaRef)
int Process(const char *code)
bool IsTypeDerivedFrom(ConstTypeRef derived, ConstTypeRef base)
void GetDatamembers(DeclRef DRef, std::vector< DeclRef > &datamembers)
void GetFnTypeSignature(ConstTypeRef fn_type, std::vector< TypeRef > &sig)
bool IsAggregate(ConstDeclRef DRef)
ObjectRef Allocate(DeclRef DRef, size_t count)
bool IsFunctionPointerType(ConstTypeRef TyRef)
TypeRef GetFunctionArgType(ConstFuncRef func, size_t iarg)
intptr_t GetVariableOffset(compat::Interpreter &I, Decl *D, CXXRecordDecl *BaseCXXRD)
TypeRef GetUnderlyingType(ConstTypeRef TyRef)
static int vtableMethodSlotCount(ConstDeclRef DRef)
bool IsSmartPtrType(ConstTypeRef TyRef)
std::string GetQualifiedCompleteName(ConstDeclRef DRef)
void AddSearchPath(const char *dir, bool isUser, bool prepend)
TypeRef GetPointerType(ConstTypeRef TyRef)
size_t GetFunctionNumArgs(ConstFuncRef func)
static void PopulateBuiltinMap(ASTContext &Context)
bool IsDebugOutputEnabled()
bool IsFloatingType(ConstTypeRef TyRef)
TypeRef GetReferencedType(ConstTypeRef TyRef, bool rvalue)
bool IsBuiltin(ConstTypeRef TyRef)
size_t GetNumBases(ConstDeclRef DRef)
static std::string GetCompleteNameImpl(ConstDeclRef DRef, bool qualified)
bool IsClass(ConstDeclRef DRef)
std::vector< long int > GetDimensions(ConstTypeRef TyRef)
bool IsPublicMethod(ConstFuncRef method)
DeclRef GetGlobalScope()
void LookupConstructors(const std::string &name, ConstDeclRef parent, std::vector< FuncRef > &funcs)
FuncRef GetDefaultConstructor(compat::Interpreter &interp, DeclRef DRef)
bool IsIntegerType(ConstTypeRef TyRef, Signedness *s)
bool IsAbstract(ConstDeclRef DRef)
void(VTableOverlayDtorHost::*)() VTableOverlayDtorSlotFn
void CppInterOpTraceJitCallInvokeDestructorImpl(const JitCall *JC, void *object, unsigned long nary, int withFree)
void GetStaticDatamembers(ConstDeclRef DRef, std::vector< DeclRef > &datamembers)
AllocType GetAllocType(ConstFuncRef Fn)
bool IsPointerType(ConstTypeRef TyRef)
std::string SearchLibrariesForSymbol(const char *mangled_name, bool search_system)
FuncRef BestOverloadFunctionMatch(const std::vector< FuncRef > &candidates, const std::vector< TemplateArgInfo > &explicit_types, const std::vector< TemplateArgInfo > &arg_types)
void GetOperator(ConstDeclRef DRef, Operator op, std::vector< FuncRef > &operators, OperatorArity kind)
bool LoadLibrary(const char *lib_stem, bool lookup)
bool IsSubclass(ConstDeclRef derived, ConstDeclRef base)
void GetEnumConstantDatamembers(ConstDeclRef DRef, std::vector< DeclRef > &datamembers, bool include_enum_class)
static bool SkipShutDown
Set by UseExternalInterpreter to suppress llvm_shutdown at process exit – the client owns LLVM in tha...
VTableOverlay * MakeVTableOverlay(void *inst, ConstDeclRef base, const ConstFuncRef *methods, void *const *overlay_fns, std::size_t n_overlays, std::size_t n_extra_prefix_slots, VTableOverlayDtorHook on_destroy, void *cleanup_data)
static unsigned ComputeBaseOffset(const ASTContext &Context, const CXXRecordDecl *DerivedRD, const CXXBasePath &Path)
InterpRef GetInterpreter()
static std::stack< StreamCaptureInfo > & GetRedirectionStack()
bool IsExplicit(ConstFuncRef method)
size_t GetEnumConstantValue(ConstDeclRef DRef)
std::string GetVersion()
static compat::Interpreter & getInterp(InterpRef I=nullptr)
std::string LookupLibrary(const char *lib_name)
bool IsProtectedVariable(ConstDeclRef var)
static void RegisterInterpreter(compat::Interpreter *I, bool Owned, std::vector< std::string > ArgvStorage={})
bool IsConstVariable(ConstDeclRef var)
void GetFunctionTemplatedDecls(ConstDeclRef DRef, std::vector< FuncRef > &methods)
bool IsFunctionProtoType(ConstTypeRef TyRef)
static void * DtorFnToSlot(VTableOverlayDtorSlotFn fn)
bool IsTypedefed(ConstDeclRef DRef)
clang::QualType GetTypeFromDecl(const clang::TypeDecl *TD)
void InstantiateClassTemplateSpecialization(Interpreter &interp, clang::ClassTemplateSpecializationDecl *CTSD)
clang::Value Value
void maybeMangleDeclName(const clang::GlobalDecl &GD, std::string &mangledName)
CppInternal::Interpreter Interpreter
void codeComplete(std::vector< std::string > &Results, clang::Interpreter &I, const char *code, unsigned complete_line=1U, unsigned complete_column=1U)
llvm::orc::LLJIT * getExecutionEngine(clang::Interpreter &I)
Cpp::Box MakeValueBox(const Value &V, void *qt) noexcept
Wrap a compat::Value into a refcount-shared K_PtrOrObj Cpp::Box.
llvm::Expected< llvm::JITTargetAddress > getSymbolAddress(clang::Interpreter &I, llvm::StringRef IRName)
Definition Paths.h:18
std::map< const clang::FunctionDecl *, void * > WrapperStore
compat::Interpreter * Interpreter
std::map< const clang::Decl *, void * > DtorWrapperStore
RAII guard whose dtor calls llvm_shutdown for the owned-interpreter case.
VTableOverlay & operator=(const VTableOverlay &)=delete
static void ** ReadVPtr(void *inst)
VTableOverlay ** hidden_slot() const
VTableOverlayDtorHook cleanup
static void WriteVPtr(void *inst, void **new_vptr)
VTableOverlayDtorSlotFn orig_dtor
std::size_t n_extra_prefix_slots
VTableOverlay(void **block, void **orig_vptr, void *inst, std::size_t n_extra)
static To BitCastFn(From f) noexcept
void ** address_point() const
VTableOverlay(const VTableOverlay &)=delete
Holds information for instantiating a template.