From c26597c528a156117a79605375aae32d7fcaf7be Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Tue, 3 Oct 2023 17:03:11 +0200 Subject: [PATCH] [cling] Emit const variables only once Otherwise they are emitted as internal and we get double-construction and -destruction on the same memory address due to the way we promote internal declarations in KeepLocalGVPass. According to upstream tests, the de-duplication doesn't work on Windows (yet), but I think this problem is severe enough to fix it on the other platforms sooner rather than later. Fixes #13429 (cherry picked from commit 2dc57866c1d18010d3ebee681cc5e7777cd4d017) --- interpreter/cling/test/CodeGeneration/const.C | 37 +++++++++++++++++++ .../src/lib/ExecutionEngine/Orc/LLJIT.cpp | 2 +- .../src/tools/clang/lib/AST/ASTContext.cpp | 9 +++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 interpreter/cling/test/CodeGeneration/const.C diff --git a/interpreter/cling/test/CodeGeneration/const.C b/interpreter/cling/test/CodeGeneration/const.C new file mode 100644 index 0000000000000..8fe1397be30d8 --- /dev/null +++ b/interpreter/cling/test/CodeGeneration/const.C @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. +//------------------------------------------------------------------------------ + +// RUN: cat %s | %cling 2>&1 | FileCheck %s + +extern "C" int printf(const char*, ...); + +struct A { + int val; + A(int v) : val(v) { + printf("A(%d), this = %p\n", val, this); + } + ~A() { + printf("~A(%d), this = %p\n", val, this); + } + int getVal() const { return val; } +}; + +const A a(1); +// CHECK: A(1), this = [[PTR:.+]] + +a.val +// CHECK-NEXT: (const int) 1 +a.getVal() +// CHECK-NEXT: (int) 1 +a.val +// CHECK-NEXT: (const int) 1 +a.getVal() +// CHECK-NEXT: (int) 1 + +// CHECK-NEXT: ~A(1), this = [[PTR]] +// CHECK-NOT: ~A diff --git a/interpreter/llvm/src/lib/ExecutionEngine/Orc/LLJIT.cpp b/interpreter/llvm/src/lib/ExecutionEngine/Orc/LLJIT.cpp index 6c52998dc633b..4d304f7bca7b8 100644 --- a/interpreter/llvm/src/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/interpreter/llvm/src/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -483,7 +483,7 @@ GlobalCtorDtorScraper::operator()(ThreadSafeModule TSM, Inits.push_back(std::make_pair(E.Func, E.Priority)); llvm::sort(Inits, [](const std::pair &LHS, const std::pair &RHS) { - return LHS.first < RHS.first; + return LHS.second < RHS.second; }); auto *EntryBlock = BasicBlock::Create(Ctx, "entry", InitFunc); IRBuilder<> IB(EntryBlock); diff --git a/interpreter/llvm/src/tools/clang/lib/AST/ASTContext.cpp b/interpreter/llvm/src/tools/clang/lib/AST/ASTContext.cpp index 00ec96abae66d..4e80e859443fc 100644 --- a/interpreter/llvm/src/tools/clang/lib/AST/ASTContext.cpp +++ b/interpreter/llvm/src/tools/clang/lib/AST/ASTContext.cpp @@ -10833,6 +10833,15 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const { static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, const VarDecl *VD) { + // As an extension for interactive REPLs, make sure constant variables are + // only emitted once instead of LinkageComputer::getLVForNamespaceScopeDecl + // marking them as internal. + if (Context.getLangOpts().CPlusPlus && + VD->getType().isConstQualified() && + !VD->getType().isVolatileQualified() && !VD->isInline() && + !isa(VD) && !VD->getDescribedVarTemplate()) + return GVA_DiscardableODR; + if (!VD->isExternallyVisible()) return GVA_Internal;