Skip to content

Commit 311f725

Browse files
committed
[clang][Interp] Create only globals when initializing a global variable
For this code: struct O { int &&j; }; O o1(0); The generated AST for the initializer of o1 is: VarDecl 0x62100006ab08 <array.cpp:119:3, col:9> col:5 o1 'O':'O' parenlistinit `-ExprWithCleanups 0x62100006b250 <col:7, col:9> 'O':'O' `-CXXParenListInitExpr 0x62100006b210 <col:7, col:9> 'O':'O' `-MaterializeTemporaryExpr 0x62100006b1f0 <col:8> 'int' xvalue `-IntegerLiteral 0x62100006abd0 <col:8> 'int' 0 Before this patch, we create a local temporary variable for the MaterializeTemporaryExpr and destroy it again when destroying the EvalEmitter we create to interpret the initializer. However, since O::j is a reference, this reference now points to a local variable that doesn't exist anymore. Differential Revision: https://reviews.llvm.org/D156453
1 parent 8505c3b commit 311f725

File tree

4 files changed

+44
-6
lines changed

4 files changed

+44
-6
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,20 @@ namespace interp {
2929
template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
3030
public:
3131
DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
32-
: VariableScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
32+
: VariableScope<Emitter>(Ctx), Scope(Ctx->P, VD),
33+
OldGlobalDecl(Ctx->GlobalDecl) {
34+
Ctx->GlobalDecl = Context::shouldBeGloballyIndexed(VD);
35+
}
3336

3437
void addExtended(const Scope::Local &Local) override {
3538
return this->addLocal(Local);
3639
}
3740

41+
~DeclScope() { this->Ctx->GlobalDecl = OldGlobalDecl; }
42+
3843
private:
3944
Program::DeclScope Scope;
45+
bool OldGlobalDecl;
4046
};
4147

4248
/// Scope used to handle initialization methods.
@@ -1198,21 +1204,30 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
11981204
if (DiscardResult)
11991205
return this->discard(SubExpr);
12001206

1207+
// When we're initializing a global variable *or* the storage duration of
1208+
// the temporary is explicitly static, create a global variable.
12011209
std::optional<PrimType> SubExprT = classify(SubExpr);
1202-
if (E->getStorageDuration() == SD_Static) {
1210+
bool IsStatic = E->getStorageDuration() == SD_Static;
1211+
if (GlobalDecl || IsStatic) {
12031212
std::optional<unsigned> GlobalIndex = P.createGlobal(E);
12041213
if (!GlobalIndex)
12051214
return false;
12061215

12071216
const LifetimeExtendedTemporaryDecl *TempDecl =
12081217
E->getLifetimeExtendedTemporaryDecl();
1209-
assert(TempDecl);
1218+
if (IsStatic)
1219+
assert(TempDecl);
12101220

12111221
if (SubExprT) {
12121222
if (!this->visit(SubExpr))
12131223
return false;
1214-
if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
1215-
return false;
1224+
if (IsStatic) {
1225+
if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
1226+
return false;
1227+
} else {
1228+
if (!this->emitInitGlobal(*SubExprT, *GlobalIndex, E))
1229+
return false;
1230+
}
12161231
return this->emitGetPtrGlobal(*GlobalIndex, E);
12171232
}
12181233

@@ -1221,7 +1236,9 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
12211236
return false;
12221237
if (!this->visitInitializer(SubExpr))
12231238
return false;
1224-
return this->emitInitGlobalTempComp(TempDecl, E);
1239+
if (IsStatic)
1240+
return this->emitInitGlobalTempComp(TempDecl, E);
1241+
return true;
12251242
}
12261243

12271244
// For everyhing else, use local variables.

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
304304
/// Flag inidicating if we're initializing an already created
305305
/// variable. This is set in visitInitializer().
306306
bool Initializing = false;
307+
308+
/// Flag indicating if we're initializing a global variable.
309+
bool GlobalDecl = false;
307310
};
308311

309312
extern template class ByteCodeExprGen<ByteCodeEmitter>;

clang/test/AST/Interp/records.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,22 @@ namespace ParenInit {
10641064
};
10651065

10661066
constexpr B b(A(1),2);
1067+
1068+
1069+
struct O {
1070+
int &&j;
1071+
};
1072+
1073+
/// Not constexpr!
1074+
O o1(0);
1075+
constinit O o2(0); // ref-error {{variable does not have a constant initializer}} \
1076+
// ref-note {{required by 'constinit' specifier}} \
1077+
// ref-note {{reference to temporary is not a constant expression}} \
1078+
// ref-note {{temporary created here}} \
1079+
// expected-error {{variable does not have a constant initializer}} \
1080+
// expected-note {{required by 'constinit' specifier}} \
1081+
// expected-note {{reference to temporary is not a constant expression}} \
1082+
// expected-note {{temporary created here}}
10671083
}
10681084
#endif
10691085

clang/test/SemaCXX/paren-list-agg-init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// RUN: %clang_cc1 -verify -std=c++20 %s -fsyntax-only
2+
// RUN: %clang_cc1 -verify -std=c++20 %s -fsyntax-only -fexperimental-new-constant-interpreter
3+
// RUN: %clang_cc1 -verify=expected,beforecxx20 -Wc++20-extensions -std=c++20 %s -fsyntax-only -fexperimental-new-constant-interpreter
24
// RUN: %clang_cc1 -verify=expected,beforecxx20 -Wc++20-extensions -std=c++20 %s -fsyntax-only
35

46
struct A { // expected-note 4{{candidate constructor}}

0 commit comments

Comments
 (0)