Skip to content

Commit

Permalink
[clang] Fix default initializers being ignored when initializing temp…
Browse files Browse the repository at this point in the history
…lated 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
  • Loading branch information
alanzhao1 committed May 1, 2023
1 parent ce357fd commit da0089c
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 7 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ Bug Fixes to C++ Support
- Fix bug in the computation of the ``__has_unique_object_representations``
builtin for types with unnamed bitfields.
(`#61336 <https://github.com/llvm/llvm-project/issues/61336>`_)
- Fix default member initializers sometimes being ignored when performing
parenthesized aggregate initialization of templated types.
(`#62266 <https://github.com/llvm/llvm-project/issues/62266>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
16 changes: 9 additions & 7 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5377,14 +5377,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:
Expand Down
23 changes: 23 additions & 0 deletions clang/test/CodeGen/paren-list-agg-init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

0 comments on commit da0089c

Please sign in to comment.