tbaeder updated this revision to Diff 471404.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136828/new/

https://reviews.llvm.org/D136828

Files:
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/Pointer.h
  clang/test/AST/Interp/cxx20.cpp

Index: clang/test/AST/Interp/cxx20.cpp
===================================================================
--- clang/test/AST/Interp/cxx20.cpp
+++ clang/test/AST/Interp/cxx20.cpp
@@ -85,8 +85,8 @@
 namespace UninitializedFields {
   class A {
   public:
-    int a; // expected-note {{subobject declared here}} \
-           // ref-note {{subobject declared here}}
+    int a; // expected-note 2{{subobject declared here}} \
+           // ref-note 2{{subobject declared here}}
     constexpr A() {}
   };
   constexpr A a; // expected-error {{must be initialized by a constant expression}} \
@@ -112,6 +112,42 @@
                      // expected-note {{in call to 'Derived()'}} \
                      // ref-error {{must be initialized by a constant expression}} \
                      // ref-note {{subobject of type 'int' is not initialized}}
+
+  class C2 {
+  public:
+    A a;
+    constexpr C2() {} // expected-note {{subobject of type 'int' is not initialized}}
+  };
+  constexpr C2 c2; // expected-error {{must be initialized by a constant expression}} \
+                   // expected-note {{in call to 'C2()'}} \
+                   // ref-error {{must be initialized by a constant expression}} \
+                   // ref-note {{subobject of type 'int' is not initialized}}
+
+
+  // FIXME: These two are currently disabled because the array fields
+  //   cannot be initialized.
+#if 0
+  class C3 {
+  public:
+    A a[2];
+    constexpr C3() {}
+  };
+  constexpr C3 c3; // expected-error {{must be initialized by a constant expression}} \
+                   // expected-note {{subobject of type 'int' is not initialized}} \
+                   // ref-error {{must be initialized by a constant expression}} \
+                   // ref-note {{subobject of type 'int' is not initialized}}
+
+  class C4 {
+  public:
+    bool B[2][3]; // expected-note {{subobject declared here}} \
+                  // ref-note {{subobject declared here}}
+    constexpr C4(){}
+  };
+  constexpr C4 c4; // expected-error {{must be initialized by a constant expression}} \
+                   // expected-note {{subobject of type 'bool' is not initialized}} \
+                   // ref-error {{must be initialized by a constant expression}} \
+                   // ref-note {{subobject of type 'bool' is not initialized}}
+#endif
 };
 
 namespace ConstThis {
Index: clang/lib/AST/Interp/Pointer.h
===================================================================
--- clang/lib/AST/Interp/Pointer.h
+++ clang/lib/AST/Interp/Pointer.h
@@ -242,6 +242,8 @@
 
   /// Returns the record descriptor of a class.
   Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+  // Returns the element record type, if this is a non-primive array.
+  Record *getElemRecord() const { return getFieldDesc()->ElemDesc->ElemRecord; }
   /// Returns the field information.
   const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
 
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -443,6 +443,48 @@
   return true;
 }
 
+static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI,
+                                           QualType SubObjType,
+                                           SourceLocation SL) {
+  S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType;
+  if (SL.isValid())
+    S.Note(SL, diag::note_constexpr_subobject_declared_here);
+}
+
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+                                   const Pointer &BasePtr, const Record *R);
+
+static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC,
+                                  const Pointer &BasePtr,
+                                  const ConstantArrayType *CAT) {
+  bool Result = true;
+  size_t NumElems = CAT->getSize().getZExtValue();
+  QualType ElemType = CAT->getElementType();
+
+  if (isa<RecordType>(ElemType.getTypePtr())) {
+    const Record *R = BasePtr.getElemRecord();
+    for (size_t I = 0; I != NumElems; ++I) {
+      Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+      Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
+    }
+  } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
+    for (size_t I = 0; I != NumElems; ++I) {
+      Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+      Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
+    }
+  } else {
+    for (size_t I = 0; I != NumElems; ++I) {
+      if (!BasePtr.atIndex(I).isInitialized()) {
+        DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType,
+                                       BasePtr.getFieldDesc()->getLocation());
+        Result = false;
+      }
+    }
+  }
+
+  return Result;
+}
+
 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
                                    const Pointer &BasePtr, const Record *R) {
   assert(R);
@@ -450,19 +492,16 @@
   // Check all fields of this record are initialized.
   for (const Record::Field &F : R->fields()) {
     Pointer FieldPtr = BasePtr.atField(F.Offset);
-    QualType FieldType = FieldPtr.getType();
+    QualType FieldType = F.Decl->getType();
 
     if (FieldType->isRecordType()) {
       Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
     } else if (FieldType->isArrayType()) {
-      // FIXME: Arrays need to be handled here as well I think.
+      const auto *CAT = cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
+      Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
     } else if (!FieldPtr.isInitialized()) {
-      const SourceInfo &SI = S.Current->getSource(OpPC);
-      S.FFDiag(SI, diag::note_constexpr_uninitialized)
-          << true << F.Decl->getType();
-      SourceLocation SubobjectLoc = F.Decl->getLocation();
-      if (SubobjectLoc.isValid())
-        S.Note(SubobjectLoc, diag::note_constexpr_subobject_declared_here);
+      DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
+                                     F.Decl->getType(), F.Decl->getLocation());
       Result = false;
     }
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to