-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[Clang] Never consider conversion from single-element braced-init-list perfect #138307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…t perfect We might prefer a template std::initializer list constructor. Fix a regression introduced by llvm#136203 llvm#136203 (comment) GCC had a similar issue and a similar fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100963
@llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesWe might prefer a template std::initializer list constructor. Fix a regression introduced by #136203 GCC had a similar issue and a similar fix Full diff: https://github.com/llvm/llvm-project/pull/138307.diff 3 Files Affected:
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 8182ce9c39685..5c155fb1dbebf 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -360,6 +360,13 @@ class Sema;
LLVM_PREFERRED_TYPE(bool)
unsigned ObjCLifetimeConversionBinding : 1;
+ /// Whether the source expression was originally a single element
+ /// braced-init-list. Such a conversion is not a perfect match,
+ /// as we prefer a std::list_initializer constructor over an exact match
+ /// constructor.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned FromBracedInitList : 1;
+
/// FromType - The type that this conversion is converting
/// from. This is an opaque pointer that can be translated into a
/// QualType.
@@ -412,6 +419,12 @@ class Sema;
bool isPerfect(const ASTContext &C) const {
if (!isIdentityConversion())
return false;
+
+ // We might prefer a std::initializer constructor,
+ // so this sequence cannot be perfect
+ if (FromBracedInitList)
+ return false;
+
// If we are not performing a reference binding, we can skip comparing
// the types, which has a noticeable performance impact.
if (!ReferenceBinding) {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index de2382ffdf1e8..312bb29d49cc3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -246,6 +246,7 @@ void StandardConversionSequence::setAsIdentityConversion() {
BindsToRvalue = false;
BindsImplicitObjectArgumentWithoutRefQualifier = false;
ObjCLifetimeConversionBinding = false;
+ FromBracedInitList = false;
CopyConstructor = nullptr;
}
@@ -1692,12 +1693,14 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// has a single element of type cv U, where U is X or a class derived
// from X, the implicit conversion sequence has Exact Match rank if U is
// X, or Conversion rank if U is derived from X.
+ bool FromListInit = false;
if (const auto *InitList = dyn_cast<InitListExpr>(From);
InitList && InitList->getNumInits() == 1 &&
!S.isInitListConstructor(Constructor)) {
const Expr *SingleInit = InitList->getInit(0);
FromType = SingleInit->getType();
FromLoc = SingleInit->getBeginLoc();
+ FromListInit = true;
} else {
FromType = From->getType();
FromLoc = From->getBeginLoc();
@@ -1715,6 +1718,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ToType);
+ ICS.Standard.FromBracedInitList = FromListInit;
ICS.Standard.CopyConstructor = Constructor;
ICS.Standard.FoundCopyConstructor = Found;
if (ToCanon != FromCanon)
@@ -4062,6 +4066,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (isa<InitListExpr>(From)) {
// Initializer lists don't have conversions as such.
User.Before.setAsIdentityConversion();
+ User.Before.FromBracedInitList = true;
} else {
if (Best->Conversions[0].isEllipsis())
User.EllipsisConversion = true;
@@ -5276,6 +5281,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding =
(RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0;
+ ICS.Standard.FromBracedInitList = false;
ICS.Standard.CopyConstructor = nullptr;
ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
};
@@ -5474,6 +5480,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
ICS.UserDefined.After.BindsToRvalue = !LValRefType;
ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.UserDefined.After.ObjCLifetimeConversionBinding = false;
+ ICS.UserDefined.After.FromBracedInitList = false;
}
return ICS;
@@ -5760,6 +5767,8 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
SCS.BindsToFunctionLvalue = false;
SCS.BindsImplicitObjectArgumentWithoutRefQualifier = false;
SCS.ObjCLifetimeConversionBinding = false;
+ SCS.FromBracedInitList = false;
+
} else
Result.setBad(BadConversionSequence::lvalue_ref_to_rvalue,
From, ToType);
@@ -5777,10 +5786,13 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// single integer.
unsigned NumInits = From->getNumInits();
if (NumInits == 1 && !isa<InitListExpr>(From->getInit(0)) &&
- !isa<EmbedExpr>(From->getInit(0)))
+ !isa<EmbedExpr>(From->getInit(0))) {
Result = TryCopyInitialization(
S, From->getInit(0), ToType, SuppressUserConversions,
InOverloadResolution, AllowObjCWritebackConversion);
+ if (Result.isStandard())
+ Result.Standard.FromBracedInitList = true;
+ }
// - if the initializer list has no elements, the implicit conversion
// sequence is the identity conversion.
else if (NumInits == 0) {
@@ -5993,6 +6005,7 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
ICS.Standard.IsLvalueReference = Method->getRefQualifier() != RQ_RValue;
ICS.Standard.BindsToFunctionLvalue = false;
ICS.Standard.BindsToRvalue = FromClassification.isRValue();
+ ICS.Standard.FromBracedInitList = false;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier
= (Method->getRefQualifier() == RQ_None);
return ICS;
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index d68a942f64050..277c5df3bb62b 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -2,6 +2,20 @@
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -fsyntax-only -verify -std=c++20 %s
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -fsyntax-only -verify -std=c++2c %s
+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 Invalid { static_assert(false, "instantiated Invalid"); }; // #err-invalid
@@ -204,3 +218,17 @@ using a = void(int &);
template <typename c> void d(c &);
void f(a);
template <class> void f(bool j) { f(&d<int>); }
+
+struct InitListAreNotPerfect {
+ InitListAreNotPerfect(int) = delete;
+ template<class T>
+ InitListAreNotPerfect(std::initializer_list<T>);
+};
+InitListAreNotPerfect InitListAreNotPerfect_test({0});
+struct InitListAreNotPerfectCpy {
+ InitListAreNotPerfectCpy();
+ InitListAreNotPerfectCpy(const InitListAreNotPerfectCpy&);
+ template <typename T> InitListAreNotPerfectCpy(std::initializer_list<T>);
+};
+
+InitListAreNotPerfectCpy InitListAreNotPerfectCpy_test({InitListAreNotPerfectCpy{}});
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -360,6 +360,13 @@ class Sema; | |||
LLVM_PREFERRED_TYPE(bool) | |||
unsigned ObjCLifetimeConversionBinding : 1; | |||
|
|||
/// Whether the source expression was originally a single element | |||
/// braced-init-list. Such a conversion is not a perfect match, | |||
/// as we prefer a std::list_initializer constructor over an exact match |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::initializer_list
:)
@@ -412,6 +419,12 @@ class Sema; | |||
bool isPerfect(const ASTContext &C) const { | |||
if (!isIdentityConversion()) | |||
return false; | |||
|
|||
// We might prefer a std::initializer constructor, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::initializer_list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oups
…t perfect (llvm#138307) We might prefer a template std::initializer list constructor. Fix a regression introduced by llvm#136203 llvm#136203 (comment) GCC had a similar issue and a similar fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100963
…t perfect (llvm#138307) We might prefer a template std::initializer list constructor. Fix a regression introduced by llvm#136203 llvm#136203 (comment) GCC had a similar issue and a similar fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100963
…t perfect (llvm#138307) We might prefer a template std::initializer list constructor. Fix a regression introduced by llvm#136203 llvm#136203 (comment) GCC had a similar issue and a similar fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100963
…t perfect (llvm#138307) We might prefer a template std::initializer list constructor. Fix a regression introduced by llvm#136203 llvm#136203 (comment) GCC had a similar issue and a similar fix https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100963
We might prefer a template std::initializer list constructor.
Fix a regression introduced by #136203
#136203 (comment)
GCC had a similar issue and a similar fix
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100963