mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 19:06:44 +00:00
[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 https://github.com/llvm/llvm-project/issues/122306
This commit is contained in:
parent
15c49b9db3
commit
2871f69052
@ -225,6 +225,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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -5189,6 +5189,16 @@ public:
|
||||
|
||||
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()); }
|
||||
|
||||
|
@ -4261,7 +4261,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);
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
71
clang/test/SemaCXX/embed-init-list.cpp
Normal file
71
clang/test/SemaCXX/embed-init-list.cpp
Normal file
@ -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__
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user