[clang] Consider aggregate bases when checking if an InitListExpr is constant (PR #80519)
Reid Kleckner via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 2 16:24:56 PST 2024
https://github.com/rnk created https://github.com/llvm/llvm-project/pull/80519
This code was correct as written prior to C++17, which allowed bases to appear in the initializer list.
Clang currently requires compound literal initializers at file scope to be constants, which is how I tested this behavior change, but I am open to other testing ideas.
This fixes at least one part of issue #80510 .
>From 6ab5ba3f970eaaea542fbed09cae17d3666df6b3 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rnk at google.com>
Date: Sat, 3 Feb 2024 00:18:42 +0000
Subject: [PATCH] wip
---
clang/lib/AST/Expr.cpp | 12 ++++++++++++
clang/test/SemaCXX/compound-literal.cpp | 20 ++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index d665a08deb47e..8852fadf79b9a 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3342,6 +3342,18 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
if (ILE->getType()->isRecordType()) {
unsigned ElementNo = 0;
RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl();
+
+ // Check bases for C++17 aggregate initializers.
+ if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (unsigned i = 0, e = CXXRD->getNumBases(); i < e; i++) {
+ if (ElementNo < ILE->getNumInits()) {
+ const Expr *Elt = ILE->getInit(ElementNo++);
+ if (!Elt->isConstantInitializer(Ctx, false, Culprit))
+ return false;
+ }
+ }
+ }
+
for (const auto *Field : RD->fields()) {
// If this is a union, skip all the fields that aren't being initialized.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
diff --git a/clang/test/SemaCXX/compound-literal.cpp b/clang/test/SemaCXX/compound-literal.cpp
index 5957099de53af..81f8b41ff0313 100644
--- a/clang/test/SemaCXX/compound-literal.cpp
+++ b/clang/test/SemaCXX/compound-literal.cpp
@@ -3,6 +3,7 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -ast-dump %s > %t-11
// RUN: FileCheck --input-file=%t-11 %s
// RUN: FileCheck --input-file=%t-11 %s --check-prefix=CHECK-CXX11
+// RUN: %clang_cc1 -verify -std=c++17 %s
// http://llvm.org/PR7905
namespace PR7905 {
@@ -108,3 +109,22 @@ int computed_with_lambda = [] {
return result;
}();
#endif
+
+#if __cplusplus >= 201703L
+namespace DynamicFileScopeLiteral {
+// This covers the case where we have a file-scope compound literal with a
+// non-constant initializer in C++. Previously, we had a bug where Clang forgot
+// to consider initializer list elements for bases.
+struct Empty {};
+struct Foo : Empty {
+ int x;
+ int y;
+};
+int f();
+Foo o = (Foo){
+ {},
+ 1,
+ f() // expected-error {{initializer element is not a compile-time constant}}
+};
+}
+#endif
More information about the cfe-commits
mailing list