tbaeder updated this revision to Diff 545131.
tbaeder marked 2 inline comments as done.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D154189/new/
https://reviews.llvm.org/D154189
Files:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/lib/AST/Interp/Descriptor.cpp
clang/lib/AST/Interp/Descriptor.h
clang/test/AST/Interp/records.cpp
Index: clang/test/AST/Interp/records.cpp
===================================================================
--- clang/test/AST/Interp/records.cpp
+++ clang/test/AST/Interp/records.cpp
@@ -931,3 +931,63 @@
O o1(0);
}
#endif
+
+
+namespace ZeroInit {
+ struct F {
+ int a;
+ };
+
+ namespace Simple {
+ struct A {
+ char a;
+ bool b;
+ int c[4];
+ float d;
+ };
+ constexpr int foo(A x) {
+ return x.a + static_cast<int>(x.b) + x.c[0] + x.c[3] + static_cast<int>(x.d);
+ }
+ static_assert(foo(A()) == 0, "");
+ }
+
+ namespace Inheritance {
+ struct F2 : F {
+ float f;
+ };
+
+ constexpr int foo(F2 f) {
+ return (int)f.f + f.a;
+ }
+ static_assert(foo(F2()) == 0, "");
+ }
+
+ namespace BitFields {
+ struct F {
+ unsigned a : 6;
+ };
+ constexpr int foo(F f) {
+ return f.a;
+ }
+ static_assert(foo(F()) == 0, "");
+ }
+
+
+#if __cplusplus >= 202002L
+ namespace Failure {
+ struct S {
+ int a;
+ F f{12};
+ };
+ constexpr int foo(S x) {
+ return x.a; // expected-note {{read of uninitialized object}} \
+ // ref-note {{read of uninitialized object}}
+ }
+ static_assert(foo(S()) == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{in call to}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{in call to}}
+ };
+#endif
+}
+
Index: clang/lib/AST/Interp/Descriptor.h
===================================================================
--- clang/lib/AST/Interp/Descriptor.h
+++ clang/lib/AST/Interp/Descriptor.h
@@ -140,6 +140,7 @@
bool IsTemporary, bool IsMutable);
QualType getType() const;
+ QualType getElemQualType() const;
SourceLocation getLocation() const;
const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
Index: clang/lib/AST/Interp/Descriptor.cpp
===================================================================
--- clang/lib/AST/Interp/Descriptor.cpp
+++ clang/lib/AST/Interp/Descriptor.cpp
@@ -289,6 +289,12 @@
llvm_unreachable("Invalid descriptor type");
}
+QualType Descriptor::getElemQualType() const {
+ assert(isArray());
+ const auto *AT = cast<ArrayType>(getType());
+ return AT->getElementType();
+}
+
SourceLocation Descriptor::getLocation() const {
if (auto *D = Source.dyn_cast<const Decl *>())
return D->getLocation();
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -222,6 +222,7 @@
/// Emits a zero initializer.
bool visitZeroInitializer(QualType QT, const Expr *E);
+ bool visitZeroRecordInitializer(const Record *R, const Expr *E);
enum class DerefKind {
/// Value is read and pushed to stack.
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1394,7 +1394,15 @@
assert(!classify(T));
if (T->isRecordType()) {
- const Function *Func = getFunction(E->getConstructor());
+ const CXXConstructorDecl *Ctor = E->getConstructor();
+
+ // Trivial zero initialization.
+ if (E->requiresZeroInitialization() && Ctor->isTrivial()) {
+ const Record *R = getRecord(E->getType());
+ return this->visitZeroRecordInitializer(R, E);
+ }
+
+ const Function *Func = getFunction(Ctor);
if (!Func)
return false;
@@ -1467,7 +1475,7 @@
return true;
}
- return false;
+ return DiscardResult ? this->emitPopPtr(E) : true;
}
template <class Emitter>
@@ -1698,6 +1706,62 @@
llvm_unreachable("unknown primitive type");
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
+ const Expr *E) {
+ assert(E);
+ assert(R);
+ // Fields
+ for (const Record::Field &Field : R->fields()) {
+ const Descriptor *D = Field.Desc;
+ if (D->isPrimitive()) {
+ QualType QT = D->getType();
+ PrimType T = classifyPrim(D->getType());
+ if (!this->visitZeroInitializer(QT, E))
+ return false;
+ if (!this->emitInitField(T, Field.Offset, E))
+ return false;
+ continue;
+ }
+
+ // TODO: Add GetPtrFieldPop and get rid of this dup.
+ if (!this->emitDupPtr(E))
+ return false;
+ if (!this->emitGetPtrField(Field.Offset, E))
+ return false;
+
+ if (D->isPrimitiveArray()) {
+ QualType ET = D->getElemQualType();
+ PrimType T = classifyPrim(ET);
+ for (uint32_t I = 0, N = D->getNumElems(); I != N; ++I) {
+ if (!this->visitZeroInitializer(ET, E))
+ return false;
+ if (!this->emitInitElem(T, I, E))
+ return false;
+ }
+ } else {
+ // FIXME: Implement class and composite array types.
+ assert(false);
+ }
+
+ if (!this->emitPopPtr(E))
+ return false;
+ }
+
+ for (const Record::Base &B : R->bases()) {
+ if (!this->emitGetPtrBase(B.Offset, E))
+ return false;
+ if (!this->visitZeroRecordInitializer(B.R, E))
+ return false;
+ if (!this->emitPopPtr(E))
+ return false;
+ }
+
+ // FIXME: Virtual bases.
+
+ return true;
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::dereference(
const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits