Author: Jonas Hahnfeld Date: 2023-10-03T11:58:23+02:00 New Revision: 05137ecfca0bd2f7fa6cd30c771dfacbb8188785
URL: https://github.com/llvm/llvm-project/commit/05137ecfca0bd2f7fa6cd30c771dfacbb8188785 DIFF: https://github.com/llvm/llvm-project/commit/05137ecfca0bd2f7fa6cd30c771dfacbb8188785.diff LOG: [clang-repl] Emit const variables only once (#65257) Disable internal linkage for const variables if IncrementalExtensions are enabled. Otherwise the variables are emitted multiple times, with multiple constructions at unique memory locations, during every PTU. Added: clang/test/Interpreter/const.cpp Modified: clang/lib/AST/ASTContext.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8917662c5336825..e3e4578ffd49e19 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11768,6 +11768,16 @@ 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 && + Context.getLangOpts().IncrementalExtensions && + VD->getType().isConstQualified() && + !VD->getType().isVolatileQualified() && !VD->isInline() && + !isa<VarTemplateSpecializationDecl>(VD) && !VD->getDescribedVarTemplate()) + return GVA_DiscardableODR; + if (!VD->isExternallyVisible()) return GVA_Internal; diff --git a/clang/test/Interpreter/const.cpp b/clang/test/Interpreter/const.cpp new file mode 100644 index 000000000000000..a4b610f1a19d842 --- /dev/null +++ b/clang/test/Interpreter/const.cpp @@ -0,0 +1,29 @@ +// UNSUPPORTED: system-aix +// RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s + +extern "C" int printf(const char*, ...); + +struct A { int val; A(int v); ~A(); void f() const; }; +A::A(int v) : val(v) { printf("A(%d), this = %p\n", val, this); } +A::~A() { printf("~A, this = %p, val = %d\n", this, val); } +void A::f() const { printf("f: this = %p, val = %d\n", this, val); } + +const A a(1); +// CHECK: A(1), this = [[THIS:0x[0-9a-f]+]] +// The constructor must only be called once! +// CHECK-NOT: A(1) + +a.f(); +// CHECK-NEXT: f: this = [[THIS]], val = 1 +a.f(); +// CHECK-NEXT: f: this = [[THIS]], val = 1 + +%quit +// There must still be no other constructor! +// CHECK-NOT: A(1) + +// At the end, we expect exactly one destructor call +// CHECK: ~A +// CHECK-SAME: this = [[THIS]], val = 1 +// CHECK-NOT: ~A _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits