summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Zhao <ayzhao@google.com>2023-04-27 15:31:51 -0700
committerTom Stellard <tstellar@redhat.com>2023-05-15 11:03:39 -0700
commitbef3459fcde7f0be0341a76bcc782799021bae70 (patch)
treea5bf5c4b3d3512cec5e62ec8bf0e3c34b746b725
parent83c2387c87e6bdb031d882cd5c588d1cbd242db4 (diff)
downloadllvm-bef3459fcde7f0be0341a76bcc782799021bae70.tar.gz
[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
-rw-r--r--clang/docs/ReleaseNotes.rst4
-rw-r--r--clang/lib/Sema/SemaInit.cpp16
-rw-r--r--clang/test/CodeGen/paren-list-agg-init.cpp23
3 files changed, 36 insertions, 7 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c255f037c9ec..105cfd9d7411 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 99801a88e3ed..44adb167dcc0 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 a860196d8f50..7e06a466b6c0 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);
+ }
+}