[CIR] Add support for globals reference variables (#182608)

These are fairly simple, particularly if they don't need special
cleanups (which is left unimplemented), but this provides init for a
global reference variable.
This commit is contained in:
Erich Keane 2026-02-24 06:23:44 -08:00 committed by GitHub
parent a9e29e7ae3
commit 06c673ed49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 325 additions and 8 deletions

View File

@ -294,5 +294,34 @@ void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl,
return;
}
errorNYI(varDecl->getSourceRange(), "global with reference type");
mlir::OpBuilder::InsertionGuard guard(builder);
auto *block = builder.createBlock(&addr.getCtorRegion());
CIRGenFunction::LexicalScope scope{*curCGF, addr.getLoc(),
builder.getInsertionBlock()};
scope.setAsGlobalInit();
builder.setInsertionPointToStart(block);
mlir::Value getGlobal = builder.createGetGlobal(addr);
Address declAddr(getGlobal, getASTContext().getDeclAlign(varDecl));
assert(performInit && "cannot have a constant initializer which needs "
"destruction for reference");
RValue rv = cgf.emitReferenceBindingToExpr(varDecl->getInit());
{
mlir::OpBuilder::InsertionGuard guard(builder);
mlir::Operation *rvalDefOp = rv.getValue().getDefiningOp();
if (rvalDefOp && rvalDefOp->getBlock()) {
mlir::Block *rvalSrcBlock = rvalDefOp->getBlock();
if (!rvalSrcBlock->empty() && isa<cir::YieldOp>(rvalSrcBlock->back())) {
mlir::Operation &front = rvalSrcBlock->front();
getGlobal.getDefiningOp()->moveBefore(&front);
builder.setInsertionPoint(cast<cir::YieldOp>(rvalSrcBlock->back()));
}
}
cgf.emitStoreOfScalar(rv.getValue(), declAddr, /*isVolatile=*/false, ty,
LValueBaseInfo{});
}
builder.setInsertionPointToEnd(block);
cir::YieldOp::create(builder, addr->getLoc());
}

View File

@ -65,6 +65,8 @@ public:
/// constant. If this succeeds, the emission must be finalized.
mlir::Attribute tryEmitForInitializer(const VarDecl &d);
mlir::Attribute emitForInitializer(const APValue &value, QualType destType);
void finalize(cir::GlobalOp gv);
// All of the "abstract" emission methods below permit the emission to

View File

@ -1657,10 +1657,13 @@ static Address createReferenceTemporary(CIRGenFunction &cgf,
}
case SD_Thread:
case SD_Static: {
cgf.cgm.errorNYI(
m->getSourceRange(),
"createReferenceTemporary: static/thread storage duration");
return Address::invalid();
auto addr =
mlir::cast<cir::GlobalOp>(cgf.cgm.getAddrOfGlobalTemporary(m, inner));
auto getGlobal = cgf.cgm.getBuilder().createGetGlobal(addr);
assert(addr.getAlignment().has_value() &&
"This should always have an alignment");
return Address(getGlobal,
clang::CharUnits::fromQuantity(addr.getAlignment().value()));
}
case SD_Dynamic:

View File

@ -1485,9 +1485,11 @@ ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *e) {
ConstantLValue ConstantLValueEmitter::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *e) {
cgm.errorNYI(e->getSourceRange(),
"ConstantLValueEmitter: materialize temporary expr");
return {};
assert(e->getStorageDuration() == SD_Static);
const Expr *inner = e->getSubExpr()->skipRValueSubobjectAdjustments();
mlir::Operation *global = cgm.getAddrOfGlobalTemporary(e, inner);
return ConstantLValue(
cgm.getBuilder().getGlobalViewAttr(mlir::cast<cir::GlobalOp>(global)));
}
//===----------------------------------------------------------------------===//
@ -1499,6 +1501,14 @@ mlir::Attribute ConstantEmitter::tryEmitForInitializer(const VarDecl &d) {
return markIfFailed(tryEmitPrivateForVarInit(d));
}
mlir::Attribute ConstantEmitter::emitForInitializer(const APValue &value,
QualType destType) {
initializeNonAbstract();
auto c = tryEmitPrivateForMemory(value, destType);
assert(c && "couldn't emit constant value non-abstractly?");
return c;
}
void ConstantEmitter::finalize(cir::GlobalOp gv) {
assert(initializedNonAbstract &&
"finalizing emitter that was used for abstract emission?");

View File

@ -2887,3 +2887,119 @@ cir::LabelOp
CIRGenModule::lookupBlockAddressInfo(cir::BlockAddrInfoAttr blockInfo) {
return blockAddressInfoToLabel.lookup(blockInfo);
}
mlir::Operation *
CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte,
const Expr *init) {
assert((mte->getStorageDuration() == SD_Static ||
mte->getStorageDuration() == SD_Thread) &&
"not a global temporary");
const auto *varDecl = cast<VarDecl>(mte->getExtendingDecl());
// If we're not materializing a subobject of the temporary, keep the
// cv-qualifiers from the type of the MaterializeTemporaryExpr.
QualType materializedType = init->getType();
if (init == mte->getSubExpr())
materializedType = mte->getType();
CharUnits align = getASTContext().getTypeAlignInChars(materializedType);
auto insertResult = materializedGlobalTemporaryMap.insert({mte, nullptr});
if (!insertResult.second)
errorNYI(mte->getSourceRange(), "duplicate materialized temporaries");
// FIXME: If an externally-visible declaration extends multiple temporaries,
// we need to give each temporary the same name in every translation unit (and
// we also need to make the temporaries externally-visible).
llvm::SmallString<256> name;
llvm::raw_svector_ostream out(name);
getCXXABI().getMangleContext().mangleReferenceTemporary(
varDecl, mte->getManglingNumber(), out);
APValue *value = nullptr;
if (mte->getStorageDuration() == SD_Static && varDecl->evaluateValue()) {
// If the initializer of the extending declaration is a constant
// initializer, we should have a cached constant initializer for this
// temporay. Note taht this m ight have a different value from the value
// computed by evaluating the initializer if the surrounding constant
// expression modifies the temporary.
value = mte->getOrCreateValue(/*MayCreate=*/false);
}
// Try evaluating it now, it might have a constant initializer
Expr::EvalResult evalResult;
if (!value && init->EvaluateAsRValue(evalResult, getASTContext()) &&
!evalResult.hasSideEffects())
value = &evalResult.Val;
assert(!cir::MissingFeatures::addressSpace());
std::optional<ConstantEmitter> emitter;
mlir::Attribute initialValue = nullptr;
bool isConstant = false;
mlir::Type type;
if (value) {
emitter.emplace(*this);
initialValue = emitter->emitForInitializer(*value, materializedType);
isConstant = materializedType.isConstantStorage(
getASTContext(), /*ExcludeCtor=*/value, /*ExcludeDtor=*/false);
type = mlir::cast<mlir::TypedAttr>(initialValue).getType();
} else {
// No initializer, the initialization will be provided when we initialize
// the declaration which performed lifetime extension.
type = getTypes().convertTypeForMem(materializedType);
}
// Create a global variable for this lifetime-extended temporary.
cir::GlobalLinkageKind linkage =
getCIRLinkageVarDefinition(varDecl, /*isConstant=*/false);
if (linkage == cir::GlobalLinkageKind::ExternalLinkage) {
const VarDecl *initVD;
if (varDecl->isStaticDataMember() && varDecl->getAnyInitializer(initVD) &&
isa<CXXRecordDecl>(initVD->getLexicalDeclContext())) {
// Temporaries defined inside a class get linkonce_odr linkage because the
// calss can be defined in multiple translation units.
errorNYI(mte->getSourceRange(), "static data member initialization");
} else {
// There is no need for this temporary to have external linkage if the
// VarDecl has external linkage.
linkage = cir::GlobalLinkageKind::InternalLinkage;
}
}
mlir::Location loc = getLoc(mte->getSourceRange());
cir::GlobalOp gv = createGlobalOp(*this, loc, name, type, isConstant);
gv.setInitialValueAttr(initialValue);
if (emitter)
emitter->finalize(gv);
// Don't assign dllimport or dllexport to local linkage globals
if (!gv.hasLocalLinkage()) {
setGVProperties(gv, varDecl);
assert(!cir::MissingFeatures::setDLLStorageClass());
}
gv.setAlignment(align.getAsAlign().value());
if (supportsCOMDAT() && gv.isWeakForLinker())
errorNYI(mte->getSourceRange(),
"Global temporary with comdat/weak linkage");
if (varDecl->getTLSKind())
errorNYI(mte->getSourceRange(),
"Global temporary with thread local storage");
mlir::Operation *cv = gv;
assert(!cir::MissingFeatures::addressSpace());
// Update the map with the new temporary. If we created a placeholder above,
// replace it with the new global now.
mlir::Operation *&entry = materializedGlobalTemporaryMap[mte];
if (entry) {
entry->replaceAllUsesWith(cv);
entry->erase();
}
entry = cv;
return cv;
}

View File

@ -117,6 +117,9 @@ private:
/// `noundef` on a return is possible.
bool hasStrictReturn(QualType retTy, const Decl *targetDecl);
llvm::DenseMap<const Expr *, mlir::Operation *>
materializedGlobalTemporaryMap;
public:
mlir::ModuleOp getModule() const { return theModule; }
CIRGenBuilderTy &getBuilder() { return builder; }
@ -658,6 +661,11 @@ public:
// Finalize CIR code generation.
void release();
/// Returns a pointer to a global variable representing a temporary with
/// static or thread storage duration.
mlir::Operation *getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte,
const Expr *init);
/// -------
/// Visibility and Linkage
/// -------

View File

@ -0,0 +1,149 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir
// RUN: FileCheck %s --input-file=%t-before.cir --check-prefixes=CIR,CIR-BEFORE
// RUN: FileCheck %s --input-file=%t.cir --check-prefixes=CIR,CIR-AFTER
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefixes=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LLVM
struct DefCtor{};
struct WithCtor{
WithCtor();
WithCtor(int);
};
struct WithCtorDtor{
WithCtorDtor();
WithCtorDtor(int);
~WithCtorDtor();
};
int globalInt;
// CIR: cir.global external @globalInt = #cir.int<0> : !s32i {alignment = 4 : i64}
// LLVM: @globalInt = global i32 0, align 4
int &globalIntRef = globalInt;
// CIR: cir.global constant external @globalIntRef = #cir.global_view<@globalInt> : !cir.ptr<!s32i> {alignment = 8 : i64}
// LLVM: @globalIntRef = constant ptr @globalInt, align 8
const int &constGlobalIntRef = 5;
// CIR: cir.global "private" external @_ZGR17constGlobalIntRef_ = #cir.int<5> : !s32i {alignment = 4 : i64}
// CIR: cir.global constant external @constGlobalIntRef = #cir.global_view<@_ZGR17constGlobalIntRef_> : !cir.ptr<!s32i> {alignment = 8 : i64}
// LLVM: @_ZGR17constGlobalIntRef_ = {{.*}}global i32 5, align 4
// LLVM: @constGlobalIntRef = constant ptr @_ZGR17constGlobalIntRef_, align 8
// CIR-BEFORE-LLP: FAIL
DefCtor defCtor{};
// CIR: cir.global external @defCtor = #cir.undef : !rec_DefCtor {alignment = 1 : i64}
// LLVM: @defCtor = global %struct.DefCtor undef, align 1
DefCtor &defCtorRef = defCtor;
// CIR: cir.global constant external @defCtorRef = #cir.global_view<@defCtor> : !cir.ptr<!rec_DefCtor> {alignment = 8 : i64}
// LLVM: @defCtorRef = constant ptr @defCtor, align 8
const DefCtor &constDefCtorRef{};
// CIR: cir.global "private" constant external @_ZGR15constDefCtorRef_ = #cir.undef : !rec_DefCtor {alignment = 1 : i64}
// CIR: cir.global constant external @constDefCtorRef = #cir.global_view<@_ZGR15constDefCtorRef_> : !cir.ptr<!rec_DefCtor> {alignment = 8 : i64}
// LLVM: @_ZGR15constDefCtorRef_ = {{.*}}constant %struct.DefCtor undef, align 1
// LLVM: @constDefCtorRef = constant ptr @_ZGR15constDefCtorRef_, align 8
WithCtor withCtor{};
// CIR-BEFORE: cir.global external @withCtor = ctor : !rec_WithCtor {
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor>
// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>) -> ()
// CIR-BEFORE-NEXT: } {alignment = 1 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER: cir.global external @withCtor = #cir.zero : !rec_WithCtor {alignment = 1 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() {
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtor : !cir.ptr<!rec_WithCtor>
// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> ()
// CIR-AFTER-NEXT: cir.return
// CIR-AFTER-NEXT: }
// LLVM: @withCtor = global %struct.WithCtor zeroinitializer, align 1
WithCtor &withCtorRef = withCtor;
// CIR: cir.global constant external @withCtorRef = #cir.global_view<@withCtor> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64}
// LLVM: @withCtorRef = constant ptr @withCtor, align 8
const WithCtor &constWithCtorRef{};
// CIR-BEFORE: cir.global external @constWithCtorRef = ctor : !cir.ptr<!rec_WithCtor> {
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-BEFORE-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor>
// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>) -> ()
// CIR-BEFORE-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-BEFORE-NEXT: } {alignment = 8 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER: cir.global external @constWithCtorRef = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() {
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef : !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-AFTER-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR16constWithCtorRef_ : !cir.ptr<!rec_WithCtor>
// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ev(%[[GET_GLOB_OBJ]]) : (!cir.ptr<!rec_WithCtor>{{.*}}) -> ()
// CIR-AFTER-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-AFTER-NEXT: cir.return
// CIR-AFTER-NEXT: }
// LLVM: @constWithCtorRef = global ptr null, align 8
const WithCtor &constWithCtorRef2{5};
// CIR-BEFORE: cir.global external @constWithCtorRef2 = ctor : !cir.ptr<!rec_WithCtor> {
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-BEFORE-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor>
// CIR-BEFORE-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i
// CIR-BEFORE-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>, !s32i) -> ()
// CIR-BEFORE-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-BEFORE-NEXT: } {alignment = 8 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER: cir.global external @constWithCtorRef2 = #cir.ptr<null> : !cir.ptr<!rec_WithCtor> {alignment = 8 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER-NEXT: cir.func internal private @__cxx_global_var_init{{.*}}() {
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @constWithCtorRef2 : !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-AFTER-NEXT: %[[GET_GLOB_OBJ:.*]] = cir.get_global @_ZGR17constWithCtorRef2_ : !cir.ptr<!rec_WithCtor>
// CIR-AFTER-NEXT: %[[FIVE:.*]] = cir.const #cir.int<5> : !s32i
// CIR-AFTER-NEXT: cir.call @_ZN8WithCtorC1Ei(%[[GET_GLOB_OBJ]], %[[FIVE]]) : (!cir.ptr<!rec_WithCtor>{{.*}}, !s32i{{.*}}) -> ()
// CIR-AFTER-NEXT: cir.store align(8) %[[GET_GLOB_OBJ]], %[[GET_GLOB]] : !cir.ptr<!rec_WithCtor>, !cir.ptr<!cir.ptr<!rec_WithCtor>>
// CIR-AFTER-NEXT: cir.return
// CIR-AFTER-NEXT: }
// LLVM: @constWithCtorRef2 = global ptr null, align 8
WithCtorDtor withCtorDtor{};
// CIR-BEFORE: cir.global external @withCtorDtor = ctor : !rec_WithCtorDtor {
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
// CIR-BEFORE-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>) -> ()
// CIR-BEFORE-NEXT: } dtor {
// CIR-BEFORE-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
// CIR-BEFORE-NEXT: cir.call @_ZN12WithCtorDtorD1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>) -> ()
// CIR-BEFORE-NEXT: } {alignment = 1 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER: cir.global external @withCtorDtor = #cir.zero : !rec_WithCtorDtor {alignment = 1 : i64, ast = #cir.var.decl.ast}
// CIR-AFTER: cir.func internal private @__cxx_global_var_init{{.*}}() {
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
// CIR-AFTER-NEXT: cir.call @_ZN12WithCtorDtorC1Ev(%[[GET_GLOB]]) : (!cir.ptr<!rec_WithCtorDtor>{{.*}}) -> ()
// CIR-AFTER-NEXT: %[[GET_GLOB:.*]] = cir.get_global @withCtorDtor : !cir.ptr<!rec_WithCtorDtor>
// CIR-AFTER-NEXT: %[[GET_DTOR:.*]] = cir.get_global @_ZN12WithCtorDtorD1Ev : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>>
// CIR-AFTER-NEXT: %[[VOID_FN_PTR:.*]] = cir.cast bitcast %[[GET_DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!rec_WithCtorDtor>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>>
// CIR-AFTER-NEXT: %[[GLOB_TO_VOID:.*]] = cir.cast bitcast %[[GET_GLOB]] : !cir.ptr<!rec_WithCtorDtor> -> !cir.ptr<!void>
// CIR-AFTER-NEXT: %[[DSO_HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8>
// CIR-AFTER-NEXT: cir.call @__cxa_atexit(%[[VOID_FN_PTR]], %[[GLOB_TO_VOID]], %[[DSO_HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>{{.*}}) -> ()
// CIR-AFTER-NEXT: cir.return
// CIR-AFTER-NEXT: }
// LLVM: @withCtorDtor = global %struct.WithCtorDtor zeroinitializer, align 1
WithCtorDtor &withCtorDtorRef = withCtorDtor;
// CIR: cir.global constant external @withCtorDtorRef = #cir.global_view<@withCtorDtor> : !cir.ptr<!rec_WithCtorDtor> {alignment = 8 : i64}
// LLVM: @withCtorDtorRef = constant ptr @withCtorDtor, align 8
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
// LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@withCtor)
// LLVM-NEXT: ret void
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
// LLVM: call void @_ZN8WithCtorC1Ev(ptr {{.*}}@_ZGR16constWithCtorRef_)
// LLVM-NEXT: store ptr @_ZGR16constWithCtorRef_, ptr @constWithCtorRef, align 8
// LLVM-NEXT: ret void
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
// LLVM: call void @_ZN8WithCtorC1Ei(ptr {{.*}}@_ZGR17constWithCtorRef2_, i32 {{.*}}5)
// LLVM-NEXT: store ptr @_ZGR17constWithCtorRef2_, ptr @constWithCtorRef2, align 8
// LLVM-NEXT: ret void
// LLVM: define internal void @__cxx_global_var_init{{.*}}()
// LLVM: call void @_ZN12WithCtorDtorC1Ev(ptr {{.*}}@withCtorDtor)
// LLVM-NEXT: call {{.*}}@__cxa_atexit(ptr {{.*}}@_ZN12WithCtorDtorD1Ev, ptr {{.*}}@withCtorDtor, ptr {{.*}}@__dso_handle)
// LLVM-NEXT: ret void
// TODO(cir): Once we get destructors for temporaries done, we should test them
// here, same as the 'const-WithCtor' examples, except with the 'withCtorDtor'
// versions.