Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 29 additions & 20 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3274,34 +3274,43 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
}

if (T->isArrayType()) {
const ConstantArrayType *CAT =
Ctx.getASTContext().getAsConstantArrayType(E->getType());
if (!CAT)
return false;

size_t NumElems = CAT->getZExtSize();
const Function *Func = getFunction(E->getConstructor());
if (!Func)
return false;

// FIXME(perf): We're calling the constructor once per array element here,
// in the old intepreter we had a special-case for trivial constructors.
for (size_t I = 0; I != NumElems; ++I) {
if (!this->emitConstUint64(I, E))
return false;
if (!this->emitArrayElemPtrUint64(E))
return false;
if (!this->emitDupPtr(E))
return false;

// Constructor arguments.
for (const auto *Arg : E->arguments()) {
if (!this->visit(Arg))
return false;
std::function<bool(QualType)> initArrayDimension;
initArrayDimension = [&](QualType T) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just initialize initArrayDimension directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't thinkt that works if it calls itself.

Copy link
Collaborator

@shafik shafik Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely missed that aspect but that is what Deducing This is for, you pass in this auto &self.

Edit: never mind, not available in C++17 except as an extension :-(

if (!T->isArrayType()) {
// Constructor arguments.
for (const auto *Arg : E->arguments()) {
if (!this->visit(Arg))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this if statement and it's body get tested by the tests? It does not look like it but maybe I misunderstand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return false case is hit when direct expression evaluation fails or when we hit the size limit of the bytecode emitter. It's not tested in the here attached test case I think, but at least the expression case is tested in an existing test.

return false;
}

return this->emitCall(Func, 0, E);
}

if (!this->emitCall(Func, 0, E))
const ConstantArrayType *CAT =
Ctx.getASTContext().getAsConstantArrayType(T);
if (!CAT)
return false;
}
return true;
QualType ElemTy = CAT->getElementType();
unsigned NumElems = CAT->getZExtSize();
for (size_t I = 0; I != NumElems; ++I) {
if (!this->emitConstUint64(I, E))
return false;
if (!this->emitArrayElemPtrUint64(E))
return false;
if (!initArrayDimension(ElemTy))
return false;
}
return this->emitPopPtr(E);
};

return initArrayDimension(E->getType());
}

return false;
Expand Down
11 changes: 11 additions & 0 deletions clang/test/AST/ByteCode/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,3 +820,14 @@ namespace FAM {
return 1;
}
}

namespace MultiDimConstructExpr {
struct a {
a *p = this;
};
struct b {
a m[3][3];
};
constexpr b d;
static_assert(d.m[2][1].p == &d.m[2][1]);
}