[clang] [clang-repl] Emit const variables only once (PR #65257)

Jonas Hahnfeld via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 6 04:12:37 PDT 2023


https://github.com/hahnjo updated https://github.com/llvm/llvm-project/pull/65257:

>From 7b52d2ad531286ca3e14c3f05da51c91fd71bd0d Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <jonas.hahnfeld at cern.ch>
Date: Wed, 6 Sep 2023 13:11:57 +0200
Subject: [PATCH] [clang-repl] Emit const variables only once

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.
---
 clang/lib/AST/ASTContext.cpp     | 10 ++++++++++
 clang/test/Interpreter/const.cpp | 29 +++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)
 create mode 100644 clang/test/Interpreter/const.cpp

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 4b1d9e86797b77..f7438e9be19ee1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -11764,6 +11764,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 00000000000000..a4b610f1a19d84
--- /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



More information about the cfe-commits mailing list