[llvm-branch-commits] [clang] bef3459 - [clang] Fix default initializers being ignored when initializing templated aggregate types

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon May 15 11:04:45 PDT 2023


Author: Alan Zhao
Date: 2023-05-15T11:03:39-07:00
New Revision: bef3459fcde7f0be0341a76bcc782799021bae70

URL: https://github.com/llvm/llvm-project/commit/bef3459fcde7f0be0341a76bcc782799021bae70
DIFF: https://github.com/llvm/llvm-project/commit/bef3459fcde7f0be0341a76bcc782799021bae70.diff

LOG: [clang] Fix default initializers being ignored when initializing templated aggregate types

Previously, when checking whether an in-class initializer exists when
performing parenthesized aggregate initialization, Clang checks that the
output of FieldDecl::getInClassInitializer() is non-null. This is
incorrect; if the field is part of a templated type, then
getInClassInitializer() will return nullptr if we haven't called
Sem::BuildCXXDefaultInitExpr(...) before, even if
FieldDecl::hasInClassInitializer() returns true. The end result is that
Clang incorrectly ignores the in class initializer and
value-initializes the field. The fix therefore is to instead call
FieldDecl::hasInClassInitializer(), which is what we do for braced init
lists [0].

Before this patch, Clang does correctly recognize the in-class field
initializer in certain cases. This is Sema::BuildCXXDefaultInitExpr(...)
populates the in class initializer of the corresponding FieldDecl
object. Therefore, if that method was previously called with the same
FieldDecl object, as can happen with a decltype(...) or a braced list
initialization, FieldDecl::getInClassInitializer() will return a
non-null expression, and the field becomes properly initialized.

Fixes 62266

[0]: https://github.com/llvm/llvm-project/blob/be5f35e24f4c15caf3c4aeccddc54c52560c28a0/clang/lib/Sema/SemaInit.cpp#L685

Reviewed By: shafik

Differential Revision: https://reviews.llvm.org/D149389

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaInit.cpp
    clang/test/CodeGen/paren-list-agg-init.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c255f037c9ecd..105cfd9d74113 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -821,6 +821,10 @@ Bug Fixes to C++ Support
 - Do not hide templated base members introduced via using-decl in derived class
   (useful specially for constrained members). (`#50886 <https://github.com/llvm/llvm-project/issues/50886>`_)
 
+- Fix default member initializers sometimes being ignored when performing
+  parenthesized aggregate initialization of templated types.
+  (`#62266 <https://github.com/llvm/llvm-project/issues/62266>`_)
+
 Concepts Specific Fixes:
 
 - Class member variables are now in scope when parsing a ``requires`` clause.

diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 99801a88e3ed3..44adb167dcc02 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5348,14 +5348,16 @@ static void TryOrBuildParenListInitialization(
           //   The remaining elements are initialized with their default member
           //   initializers, if any
           auto *FD = cast<FieldDecl>(SubEntity.getDecl());
-          if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) {
-            ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD);
-            if (DIE.isInvalid())
-              return false;
-            S.checkInitializerLifetime(SubEntity, DIE.get());
-            InitExprs.push_back(DIE.get());
+          if (FD->hasInClassInitializer()) {
+            if (!VerifyOnly) {
+              ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD);
+              if (DIE.isInvalid())
+                return false;
+              S.checkInitializerLifetime(SubEntity, DIE.get());
+              InitExprs.push_back(DIE.get());
+            }
             continue;
-          };
+          }
         }
         // Remaining class elements without default member initializers and
         // array elements are value initialized:

diff  --git a/clang/test/CodeGen/paren-list-agg-init.cpp b/clang/test/CodeGen/paren-list-agg-init.cpp
index a860196d8f500..7e06a466b6c0a 100644
--- a/clang/test/CodeGen/paren-list-agg-init.cpp
+++ b/clang/test/CodeGen/paren-list-agg-init.cpp
@@ -90,6 +90,15 @@ namespace gh61145 {
   };
 }
 
+namespace gh62266 {
+  // CHECK-DAG: [[STRUCT_H:%.*H.*]] = type { i32, i32 }
+  template <int J>
+  struct H {
+    int i;
+    int j = J;
+  };
+}
+
 // CHECK-DAG: [[A1:@.*a1.*]] = internal constant [[STRUCT_A]] { i8 3, double 2.000000e+00 }, align 8
 constexpr A a1(3.1, 2.0);
 // CHECK-DAG: [[A2:@.*a2.*]] = internal constant [[STRUCT_A]] { i8 99, double 0.000000e+00 }, align 8
@@ -421,3 +430,17 @@ namespace gh61145 {
     make2<0>();
   }
 }
+
+namespace gh62266 {
+  // CHECK: define {{.*}} void {{.*foo20.*}}
+  // CHECK-NEXT: entry:
+  // CHECK-NEXT: [[H:%.*h.*]] = alloca [[STRUCT_H]], align 4
+  // CHECK-NEXT: [[I:%.*i.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[H]], i32 0, i32 0
+  // CHECK-NEXT: store i32 1, ptr [[I]], align 4
+  // CHECK-NEXT: [[J:%.*j.*]] = getelementptr inbounds [[STRUCT_H]], ptr [[H]], i32 0, i32 1
+  // CHECK-NEXT: store i32 2, ptr [[J]], align 4
+  // CHECK-NEXT: ret void
+  void foo20() {
+    H<2> h(1);
+  }
+}


        


More information about the llvm-branch-commits mailing list