Skip to content

Commit 21e8bb8

Browse files
committed
PR48606: The lifetime of a constexpr heap allocation always started
during the same evaluation. It looks like the only case for which this matters is determining whether mutable subobjects of a heap allocation can be modified during constant evaluation.
1 parent c945dc4 commit 21e8bb8

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

clang/lib/AST/ExprConstant.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -3497,8 +3497,8 @@ static bool diagnoseMutableFields(EvalInfo &Info, const Expr *E, AccessKinds AK,
34973497
static bool lifetimeStartedInEvaluation(EvalInfo &Info,
34983498
APValue::LValueBase Base,
34993499
bool MutableSubobject = false) {
3500-
// A temporary we created.
3501-
if (Base.getCallIndex())
3500+
// A temporary or transient heap allocation we created.
3501+
if (Base.getCallIndex() || Base.is<DynamicAllocLValue>())
35023502
return true;
35033503

35043504
switch (Info.IsEvaluatingDecl) {

clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,37 @@ constexpr bool construct_after_lifetime_2() {
176176
return true;
177177
}
178178
static_assert(construct_after_lifetime_2()); // expected-error {{}} expected-note {{in call}}
179+
180+
namespace PR48606 {
181+
struct A { mutable int n = 0; };
182+
183+
constexpr bool f() {
184+
A a;
185+
A *p = &a;
186+
p->~A();
187+
std::construct_at<A>(p);
188+
return true;
189+
}
190+
static_assert(f());
191+
192+
constexpr bool g() {
193+
A *p = new A;
194+
p->~A();
195+
std::construct_at<A>(p);
196+
delete p;
197+
return true;
198+
}
199+
static_assert(g());
200+
201+
constexpr bool h() {
202+
std::allocator<A> alloc;
203+
A *p = alloc.allocate(1);
204+
std::construct_at<A>(p);
205+
p->~A();
206+
std::construct_at<A>(p);
207+
p->~A();
208+
alloc.deallocate(p);
209+
return true;
210+
}
211+
static_assert(h());
212+
}

0 commit comments

Comments
 (0)