Skip to content

Commit 7b52d2a

Browse files
committed
[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.
1 parent 74f985b commit 7b52d2a

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
@@ -11764,6 +11764,16 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
1176411764

1176511765
static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
1176611766
const VarDecl *VD) {
11767+
// As an extension for interactive REPLs, make sure constant variables are
11768+
// only emitted once instead of LinkageComputer::getLVForNamespaceScopeDecl
11769+
// marking them as internal.
11770+
if (Context.getLangOpts().CPlusPlus &&
11771+
Context.getLangOpts().IncrementalExtensions &&
11772+
VD->getType().isConstQualified() &&
11773+
!VD->getType().isVolatileQualified() && !VD->isInline() &&
11774+
!isa<VarTemplateSpecializationDecl>(VD) && !VD->getDescribedVarTemplate())
11775+
return GVA_DiscardableODR;
11776+
1176711777
if (!VD->isExternallyVisible())
1176811778
return GVA_Internal;
1176911779

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)