Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 1 addition & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr");
}
void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitMaterializeTemporaryExpr");
Visit(e->getSubExpr());
}
void VisitOpaqueValueExpr(OpaqueValueExpr *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
Expand Down
24 changes: 21 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,9 +1069,27 @@ class ConstExprEmitter

mlir::Attribute VisitCXXConstructExpr(CXXConstructExpr *e, QualType ty) {
if (!e->getConstructor()->isTrivial())
return nullptr;
cgm.errorNYI(e->getBeginLoc(), "trivial constructor const handling");
return {};
return {};

// Only default and copy/move constructors can be trivial.
if (e->getNumArgs()) {
assert(e->getNumArgs() == 1 && "trivial ctor with > 1 argument");
assert(e->getConstructor()->isCopyOrMoveConstructor() &&
"trivial ctor has argument but isn't a copy/move ctor");

Expr *arg = e->getArg(0);
assert(cgm.getASTContext().hasSameUnqualifiedType(ty, arg->getType()) &&
"argument to copy ctor is of wrong type");

// Look through the temporary; it's just converting the value to an lvalue
// to pass it to the constructor.
if (auto const *mte = dyn_cast<MaterializeTemporaryExpr>(arg))
return Visit(mte->getSubExpr(), ty);
// Don't try to support arbitrary lvalue-to-rvalue conversions for now.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be a not-yet-implemented or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment is carried over from classic codegen, which does the same thing here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh weird... Can you replace the dyn_cast with a cast in classic codegen? Does it hit anything? I'm actually pretty concerned by this...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I report and error after the dyn_cast falls through in classic codegen, it fires 14 times in eight tests in the CodeGenCXX tests:

GUID thing = (side_effect(), __uuidof(Curly));


(void) new std::initializer_list<int> {i, 2, 3};

(void) new std::initializer_list<destroyme1> {destroyme1(), destroyme1()};


auto x = std::initializer_list<S>{ S(), S() };

SelfReference self_reference_2 = {self_reference_1};


static auto [x1, x2] = make<A>();

static auto [x1, x2] = make<B>();

X2< B > bg = X1< X2< B > >::get();

I haven't looked at these in detail yet, but I know that we can get here if the constructor argument is not a constant, and if we do then returning nullptr is the correct behavior.

The only case that would be a problem is if the argument is not a MaterializeTemporaryExpr but is a constant, and even in that case if we return null here, something else is going to handle it, though possibly not correctly.

I also tried inserting a call to ConstantExprEmitter::Visit(Arg, Ty) in the case where the dyn_cast failed, and that doesn't change anything.

Copy link
Member

Choose a reason for hiding this comment

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

One possible alternative is to add a missing feature as a way to track what needs to be investigated into both CodeGen paths.

return {};
}

return cgm.getBuilder().getZeroInitAttr(cgm.convertType(ty));
}

mlir::Attribute VisitStringLiteral(StringLiteral *e, QualType t) {
Expand Down
44 changes: 44 additions & 0 deletions clang/test/CIR/CodeGen/trivial-ctor-const-init.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++11 -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG

struct StructWithDefaultCtor {
int n;
};

StructWithDefaultCtor defCtor = StructWithDefaultCtor();

// CIR: cir.global {{.*}} @defCtor = #cir.zero : !rec_StructWithDefaultCtor
// LLVM: @defCtor = global %struct.StructWithDefaultCtor zeroinitializer
// OGCG: @defCtor = global %struct.StructWithDefaultCtor zeroinitializer

struct StructWithCtorArg {
double value;
StructWithCtorArg(const double& x) : value(x) {}
};

StructWithCtorArg withArg = 0.0;

// CIR: cir.global {{.*}} @withArg = #cir.zero : !rec_StructWithCtorArg
// LLVM: @withArg = global %struct.StructWithCtorArg zeroinitializer
// OGCG: @withArg = global %struct.StructWithCtorArg zeroinitializer

// CIR: cir.func {{.*}} @__cxx_global_var_init()
// CIR: %[[TMP0:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["ref.tmp0"]
// CIR: %[[WITH_ARG:.*]] = cir.get_global @withArg : !cir.ptr<!rec_StructWithCtorArg>
// CIR: %[[ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.double
// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP0]] : !cir.double, !cir.ptr<!cir.double>
// CIR: cir.call @_ZN17StructWithCtorArgC1ERKd(%[[WITH_ARG]], %[[TMP0]]) : (!cir.ptr<!rec_StructWithCtorArg>, !cir.ptr<!cir.double>) -> ()

// LLVM: define {{.*}} void @__cxx_global_var_init()
// LLVM: %[[TMP0:.*]] = alloca double
// LLVM: store double 0.000000e+00, ptr %[[TMP0]]
// LLVM: call void @_ZN17StructWithCtorArgC1ERKd(ptr @withArg, ptr %[[TMP0]])

// OGCG: define {{.*}} void @__cxx_global_var_init()
// OGCG: %[[TMP0:.*]] = alloca double
// OGCG: store double 0.000000e+00, ptr %[[TMP0]]
// OGCG: call void @_ZN17StructWithCtorArgC1ERKd(ptr {{.*}} @withArg, ptr {{.*}} %[[TMP0]])
Loading