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