[clang] [clang] Fix issues with #embed and intializer lists/template arguments (PR #128890)

Mariya Podchishchaeva via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 27 02:13:44 PST 2025


https://github.com/Fznamznon updated https://github.com/llvm/llvm-project/pull/128890

>From 90977892092a206e120cdfea2960d2fb7929ef44 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Thu, 20 Feb 2025 03:43:23 -0800
Subject: [PATCH 1/2] [clang] Fix issues with #embed and intializer
 lists/template arguments

Sometimes number of expressions in InitListExpr is used for template
argument deduction. So, in these cases we need to pay attention to real number
of expressions including expanded #embed data.

Fixes https://github.com/llvm/llvm-project/issues/122306
---
 clang/include/clang/AST/Expr.h           | 10 ++++
 clang/lib/Sema/SemaInit.cpp              |  2 +-
 clang/lib/Sema/SemaOverload.cpp          | 12 ++--
 clang/lib/Sema/SemaTemplateDeduction.cpp |  3 +-
 clang/test/SemaCXX/embed-init-list.cpp   | 71 ++++++++++++++++++++++++
 5 files changed, 91 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/SemaCXX/embed-init-list.cpp

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 0f98d237dcbcd..cfe49acf20b77 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -5189,6 +5189,16 @@ class InitListExpr : public Expr {
 
   unsigned getNumInits() const { return InitExprs.size(); }
 
+  /// getNumInits but if the list has an EmbedExpr inside includes full length
+  /// of embedded data.
+  unsigned getNumInitsWithEmbedExpanded() const {
+    unsigned Sum = InitExprs.size();
+    for (auto *IE : InitExprs)
+      if (auto *EE = dyn_cast<EmbedExpr>(IE))
+        Sum += EE->getDataElementCount() - 1;
+    return Sum;
+  }
+
   /// Retrieve the set of initializers.
   Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); }
 
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 340e51adf190d..2387bb4e5b9ae 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -4260,7 +4260,7 @@ static bool TryInitializerListConstruction(Sema &S,
   QualType ArrayType = S.Context.getConstantArrayType(
       E.withConst(),
       llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
-                  List->getNumInits()),
+                  List->getNumInitsWithEmbedExpanded()),
       nullptr, clang::ArraySizeModifier::Normal, 0);
   InitializedEntity HiddenArray =
       InitializedEntity::InitializeTemporary(ArrayType);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 08586b4908dd4..c344b6fff40c6 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5710,12 +5710,14 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
     //    - if the initializer list has one element that is not itself an
     //      initializer list, the implicit conversion sequence is the one
     //      required to convert the element to the parameter type.
+    // Bail out on EmbedExpr as well since we never create EmbedExpr for a
+    // single integer.
     unsigned NumInits = From->getNumInits();
-    if (NumInits == 1 && !isa<InitListExpr>(From->getInit(0)))
-      Result = TryCopyInitialization(S, From->getInit(0), ToType,
-                                     SuppressUserConversions,
-                                     InOverloadResolution,
-                                     AllowObjCWritebackConversion);
+    if (NumInits == 1 && !isa<InitListExpr>(From->getInit(0)) &&
+        !isa<EmbedExpr>(From->getInit(0)))
+      Result = TryCopyInitialization(
+          S, From->getInit(0), ToType, SuppressUserConversions,
+          InOverloadResolution, AllowObjCWritebackConversion);
     //    - if the initializer list has no elements, the implicit conversion
     //      sequence is the identity conversion.
     else if (NumInits == 0) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 627cd82ed1c77..dbd73ead8a63f 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4506,7 +4506,8 @@ static TemplateDeductionResult DeduceFromInitializerList(
       // C++ [temp.deduct.type]p13:
       //   The type of N in the type T[N] is std::size_t.
       QualType T = S.Context.getSizeType();
-      llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits());
+      llvm::APInt Size(S.Context.getIntWidth(T),
+                       ILE->getNumInitsWithEmbedExpanded());
       if (auto Result = DeduceNonTypeTemplateArgument(
               S, TemplateParams, NTTP, llvm::APSInt(Size), T,
               /*ArrayBound=*/true, Info, /*PartialOrdering=*/false, Deduced,
diff --git a/clang/test/SemaCXX/embed-init-list.cpp b/clang/test/SemaCXX/embed-init-list.cpp
new file mode 100644
index 0000000000000..c511ca707a537
--- /dev/null
+++ b/clang/test/SemaCXX/embed-init-list.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c23-extensions %s
+// expected-no-diagnostics
+
+namespace std {
+typedef decltype(sizeof(int)) size_t;
+
+template <class _E> class initializer_list {
+  const _E *__begin_;
+  size_t __size_;
+
+  constexpr initializer_list(const _E *__b, size_t __s)
+      : __begin_(__b), __size_(__s) {}
+
+public:
+  constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+};
+} // namespace std
+
+template <typename T> struct S {
+  S(std::initializer_list<T>);
+};
+
+template <> struct S<char> {
+  S(std::initializer_list<char>);
+};
+
+struct S1 {
+  S<char> data;
+  int a;
+};
+
+template <typename _Tp, std::size_t _Nm> void to_array(_Tp (&&__a)[_Nm]) {}
+
+
+template<typename T>
+void tfn(T) {}
+
+void tests() {
+
+  S<char>{{
+#embed __FILE__
+  }};
+
+  S1 ss{std::initializer_list<char>{
+#embed __FILE__
+  }};
+
+  S sss = {
+#embed __FILE__
+  };
+
+  std::initializer_list<int> il{
+#embed __FILE__
+  };
+
+  static constexpr auto initializer_list = std::initializer_list<char>{
+#embed __FILE__
+      , '\0'};
+
+  static constexpr auto intinitializer_list = std::initializer_list<int>{
+#embed __FILE__
+      , '\0'};
+
+  to_array({
+#embed __FILE__
+  });
+
+  tfn<std::initializer_list<int>>({
+#embed __FILE__
+  });
+}

>From 3cf136ee719525bbca4c97bacd2ec77ead02ce52 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Thu, 27 Feb 2025 02:12:54 -0800
Subject: [PATCH 2/2] Add changelog

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 65e411cb816eb..550cdb5ff6466 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -210,6 +210,8 @@ Bug Fixes in This Version
 
 - Clang now outputs correct values when #embed data contains bytes with negative
   signed char values (#GH102798).
+- Fixed rejects-valid problem when #embed appears in std::initializer_list or
+  when it can affect template argument deduction (#GH122306).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



More information about the cfe-commits mailing list