Skip to content

Commit 2871f69

Browse files
authored
[clang] Fix issues with #embed and intializer lists/template arguments (#128890)
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 #122306
1 parent 15c49b9 commit 2871f69

File tree

6 files changed

+93
-7
lines changed

6 files changed

+93
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ Bug Fixes in This Version
225225

226226
- Clang now outputs correct values when #embed data contains bytes with negative
227227
signed char values (#GH102798).
228+
- Fixed rejects-valid problem when #embed appears in std::initializer_list or
229+
when it can affect template argument deduction (#GH122306).
228230

229231
Bug Fixes to Compiler Builtins
230232
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/Expr.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5189,6 +5189,16 @@ class InitListExpr : public Expr {
51895189

51905190
unsigned getNumInits() const { return InitExprs.size(); }
51915191

5192+
/// getNumInits but if the list has an EmbedExpr inside includes full length
5193+
/// of embedded data.
5194+
unsigned getNumInitsWithEmbedExpanded() const {
5195+
unsigned Sum = InitExprs.size();
5196+
for (auto *IE : InitExprs)
5197+
if (auto *EE = dyn_cast<EmbedExpr>(IE))
5198+
Sum += EE->getDataElementCount() - 1;
5199+
return Sum;
5200+
}
5201+
51925202
/// Retrieve the set of initializers.
51935203
Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); }
51945204

clang/lib/Sema/SemaInit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4261,7 +4261,7 @@ static bool TryInitializerListConstruction(Sema &S,
42614261
QualType ArrayType = S.Context.getConstantArrayType(
42624262
E.withConst(),
42634263
llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
4264-
List->getNumInits()),
4264+
List->getNumInitsWithEmbedExpanded()),
42654265
nullptr, clang::ArraySizeModifier::Normal, 0);
42664266
InitializedEntity HiddenArray =
42674267
InitializedEntity::InitializeTemporary(ArrayType);

clang/lib/Sema/SemaOverload.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5710,12 +5710,14 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
57105710
// - if the initializer list has one element that is not itself an
57115711
// initializer list, the implicit conversion sequence is the one
57125712
// required to convert the element to the parameter type.
5713+
// Bail out on EmbedExpr as well since we never create EmbedExpr for a
5714+
// single integer.
57135715
unsigned NumInits = From->getNumInits();
5714-
if (NumInits == 1 && !isa<InitListExpr>(From->getInit(0)))
5715-
Result = TryCopyInitialization(S, From->getInit(0), ToType,
5716-
SuppressUserConversions,
5717-
InOverloadResolution,
5718-
AllowObjCWritebackConversion);
5716+
if (NumInits == 1 && !isa<InitListExpr>(From->getInit(0)) &&
5717+
!isa<EmbedExpr>(From->getInit(0)))
5718+
Result = TryCopyInitialization(
5719+
S, From->getInit(0), ToType, SuppressUserConversions,
5720+
InOverloadResolution, AllowObjCWritebackConversion);
57195721
// - if the initializer list has no elements, the implicit conversion
57205722
// sequence is the identity conversion.
57215723
else if (NumInits == 0) {

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4506,7 +4506,8 @@ static TemplateDeductionResult DeduceFromInitializerList(
45064506
// C++ [temp.deduct.type]p13:
45074507
// The type of N in the type T[N] is std::size_t.
45084508
QualType T = S.Context.getSizeType();
4509-
llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits());
4509+
llvm::APInt Size(S.Context.getIntWidth(T),
4510+
ILE->getNumInitsWithEmbedExpanded());
45104511
if (auto Result = DeduceNonTypeTemplateArgument(
45114512
S, TemplateParams, NTTP, llvm::APSInt(Size), T,
45124513
/*ArrayBound=*/true, Info, /*PartialOrdering=*/false, Deduced,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c23-extensions %s
2+
// expected-no-diagnostics
3+
4+
namespace std {
5+
typedef decltype(sizeof(int)) size_t;
6+
7+
template <class _E> class initializer_list {
8+
const _E *__begin_;
9+
size_t __size_;
10+
11+
constexpr initializer_list(const _E *__b, size_t __s)
12+
: __begin_(__b), __size_(__s) {}
13+
14+
public:
15+
constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
16+
};
17+
} // namespace std
18+
19+
template <typename T> struct S {
20+
S(std::initializer_list<T>);
21+
};
22+
23+
template <> struct S<char> {
24+
S(std::initializer_list<char>);
25+
};
26+
27+
struct S1 {
28+
S<char> data;
29+
int a;
30+
};
31+
32+
template <typename _Tp, std::size_t _Nm> void to_array(_Tp (&&__a)[_Nm]) {}
33+
34+
35+
template<typename T>
36+
void tfn(T) {}
37+
38+
void tests() {
39+
40+
S<char>{{
41+
#embed __FILE__
42+
}};
43+
44+
S1 ss{std::initializer_list<char>{
45+
#embed __FILE__
46+
}};
47+
48+
S sss = {
49+
#embed __FILE__
50+
};
51+
52+
std::initializer_list<int> il{
53+
#embed __FILE__
54+
};
55+
56+
static constexpr auto initializer_list = std::initializer_list<char>{
57+
#embed __FILE__
58+
, '\0'};
59+
60+
static constexpr auto intinitializer_list = std::initializer_list<int>{
61+
#embed __FILE__
62+
, '\0'};
63+
64+
to_array({
65+
#embed __FILE__
66+
});
67+
68+
tfn<std::initializer_list<int>>({
69+
#embed __FILE__
70+
});
71+
}

0 commit comments

Comments
 (0)