Skip to content

Commit 05137ec

Browse files
authored
[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.
1 parent f89b7a9 commit 05137ec

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

clang/lib/AST/ASTContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11768,6 +11768,16 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
1176811768

1176911769
static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
1177011770
const VarDecl *VD) {
11771+
// As an extension for interactive REPLs, make sure constant variables are
11772+
// only emitted once instead of LinkageComputer::getLVForNamespaceScopeDecl
11773+
// marking them as internal.
11774+
if (Context.getLangOpts().CPlusPlus &&
11775+
Context.getLangOpts().IncrementalExtensions &&
11776+
VD->getType().isConstQualified() &&
11777+
!VD->getType().isVolatileQualified() && !VD->isInline() &&
11778+
!isa<VarTemplateSpecializationDecl>(VD) && !VD->getDescribedVarTemplate())
11779+
return GVA_DiscardableODR;
11780+
1177111781
if (!VD->isExternallyVisible())
1177211782
return GVA_Internal;
1177311783

clang/test/Interpreter/const.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// UNSUPPORTED: system-aix
2+
// RUN: cat %s | clang-repl | FileCheck %s
3+
// RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s
4+
5+
extern "C" int printf(const char*, ...);
6+
7+
struct A { int val; A(int v); ~A(); void f() const; };
8+
A::A(int v) : val(v) { printf("A(%d), this = %p\n", val, this); }
9+
A::~A() { printf("~A, this = %p, val = %d\n", this, val); }
10+
void A::f() const { printf("f: this = %p, val = %d\n", this, val); }
11+
12+
const A a(1);
13+
// CHECK: A(1), this = [[THIS:0x[0-9a-f]+]]
14+
// The constructor must only be called once!
15+
// CHECK-NOT: A(1)
16+
17+
a.f();
18+
// CHECK-NEXT: f: this = [[THIS]], val = 1
19+
a.f();
20+
// CHECK-NEXT: f: this = [[THIS]], val = 1
21+
22+
%quit
23+
// There must still be no other constructor!
24+
// CHECK-NOT: A(1)
25+
26+
// At the end, we expect exactly one destructor call
27+
// CHECK: ~A
28+
// CHECK-SAME: this = [[THIS]], val = 1
29+
// CHECK-NOT: ~A

0 commit comments

Comments
 (0)