[cfe-commits] r147156 - in /cfe/trunk: include/clang/Sema/Initialization.h lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/cxx0x-initializer-constructor.cpp
Sebastian Redl
sebastian.redl at getdesigned.at
Thu Dec 22 10:58:38 PST 2011
Author: cornedbee
Date: Thu Dec 22 12:58:38 2011
New Revision: 147156
URL: http://llvm.org/viewvc/llvm-project?rev=147156&view=rev
Log:
Overloading for initializer list construction.
Modified:
cfe/trunk/include/clang/Sema/Initialization.h
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Thu Dec 22 12:58:38 2011
@@ -643,8 +643,10 @@
FK_InitListBadDestinationType,
/// \brief Overloading for a user-defined conversion failed.
FK_UserConversionOverloadFailed,
- /// \brief Overloaded for initialization by constructor failed.
+ /// \brief Overloading for initialization by constructor failed.
FK_ConstructorOverloadFailed,
+ /// \brief Overloading for list-initialization by constructor failed.
+ FK_ListConstructorOverloadFailed,
/// \brief Default-initialization of a 'const' object.
FK_DefaultInitOfConst,
/// \brief Initialization of an incomplete type.
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Dec 22 12:58:38 2011
@@ -2436,6 +2436,7 @@
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
case FK_ConstructorOverloadFailed:
+ case FK_ListConstructorOverloadFailed:
return FailedOverloadResult == OR_Ambiguous;
}
@@ -2849,8 +2850,8 @@
Args, NumArgs, CandidateSet,
/*SuppressUserConversions*/ false);
Sequence.SetOverloadFailure(
- InitializationSequence::FK_ConstructorOverloadFailed,
- OR_Deleted);
+ InitializationSequence::FK_ListConstructorOverloadFailed,
+ OR_Deleted);
} else
Sequence.AddConstructorInitializationStep(DefaultConstructor,
DefaultConstructor->getAccess(),
@@ -2961,8 +2962,9 @@
OverloadCandidateSet::iterator Best;
if (OverloadingResult Result
= CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
- Sequence.SetOverloadFailure(
- InitializationSequence::FK_ConstructorOverloadFailed,
+ Sequence.SetOverloadFailure(FromInitList ?
+ InitializationSequence::FK_ListConstructorOverloadFailed :
+ InitializationSequence::FK_ConstructorOverloadFailed,
Result);
return;
}
@@ -5428,12 +5430,20 @@
<< (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
break;
+ case FK_ListConstructorOverloadFailed:
case FK_ConstructorOverloadFailed: {
SourceRange ArgsRange;
if (NumArgs)
ArgsRange = SourceRange(Args[0]->getLocStart(),
Args[NumArgs - 1]->getLocEnd());
+ if (Failure == FK_ListConstructorOverloadFailed) {
+ assert(NumArgs == 1 && "List construction from other than 1 argument.");
+ InitListExpr *InitList = cast<InitListExpr>(Args[0]);
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ }
+
// FIXME: Using "DestType" for the entity we're printing is probably
// bad.
switch (FailedOverloadResult) {
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Dec 22 12:58:38 2011
@@ -824,6 +824,86 @@
return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
}
+/// \brief Tries a user-defined conversion from From to ToType.
+///
+/// Produces an implicit conversion sequence for when a standard conversion
+/// is not an option. See TryImplicitConversion for more information.
+static ImplicitConversionSequence
+TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool AllowExplicit,
+ bool InOverloadResolution,
+ bool CStyle,
+ bool AllowObjCWritebackConversion) {
+ ImplicitConversionSequence ICS;
+
+ if (SuppressUserConversions) {
+ // We're not in the case above, so there is no conversion that
+ // we can perform.
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ // Attempt user-defined conversion.
+ OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadingResult UserDefResult
+ = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
+ AllowExplicit);
+
+ if (UserDefResult == OR_Success) {
+ ICS.setUserDefined();
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
+ QualType FromCanon
+ = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
+ QualType ToCanon
+ = S.Context.getCanonicalType(ToType).getUnqualifiedType();
+ if (Constructor->isCopyConstructor() &&
+ (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
+ // Turn this into a "standard" conversion sequence, so that it
+ // gets ranked with standard conversion sequences.
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.setFromType(From->getType());
+ ICS.Standard.setAllToTypes(ToType);
+ ICS.Standard.CopyConstructor = Constructor;
+ if (ToCanon != FromCanon)
+ ICS.Standard.Second = ICK_Derived_To_Base;
+ }
+ }
+
+ // C++ [over.best.ics]p4:
+ // However, when considering the argument of a user-defined
+ // conversion function that is a candidate by 13.3.1.3 when
+ // invoked for the copying of the temporary in the second step
+ // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
+ // 13.3.1.6 in all cases, only standard conversion sequences and
+ // ellipsis conversion sequences are allowed.
+ if (SuppressUserConversions && ICS.isUserDefined()) {
+ ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
+ }
+ } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
+ ICS.setAmbiguous();
+ ICS.Ambiguous.setFromType(From->getType());
+ ICS.Ambiguous.setToType(ToType);
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ } else {
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ }
+
+ return ICS;
+}
+
/// TryImplicitConversion - Attempt to perform an implicit conversion
/// from the given expression (Expr) to the given type (ToType). This
/// function returns an implicit conversion sequence that can be used
@@ -899,71 +979,9 @@
return ICS;
}
- if (SuppressUserConversions) {
- // We're not in the case above, so there is no conversion that
- // we can perform.
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- return ICS;
- }
-
- // Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc());
- OverloadingResult UserDefResult
- = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
- AllowExplicit);
-
- if (UserDefResult == OR_Success) {
- ICS.setUserDefined();
- // C++ [over.ics.user]p4:
- // A conversion of an expression of class type to the same class
- // type is given Exact Match rank, and a conversion of an
- // expression of class type to a base class of that type is
- // given Conversion rank, in spite of the fact that a copy
- // constructor (i.e., a user-defined conversion function) is
- // called for those cases.
- if (CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
- QualType FromCanon
- = S.Context.getCanonicalType(From->getType().getUnqualifiedType());
- QualType ToCanon
- = S.Context.getCanonicalType(ToType).getUnqualifiedType();
- if (Constructor->isCopyConstructor() &&
- (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
- // Turn this into a "standard" conversion sequence, so that it
- // gets ranked with standard conversion sequences.
- ICS.setStandard();
- ICS.Standard.setAsIdentityConversion();
- ICS.Standard.setFromType(From->getType());
- ICS.Standard.setAllToTypes(ToType);
- ICS.Standard.CopyConstructor = Constructor;
- if (ToCanon != FromCanon)
- ICS.Standard.Second = ICK_Derived_To_Base;
- }
- }
-
- // C++ [over.best.ics]p4:
- // However, when considering the argument of a user-defined
- // conversion function that is a candidate by 13.3.1.3 when
- // invoked for the copying of the temporary in the second step
- // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
- // 13.3.1.6 in all cases, only standard conversion sequences and
- // ellipsis conversion sequences are allowed.
- if (SuppressUserConversions && ICS.isUserDefined()) {
- ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
- }
- } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
- ICS.setAmbiguous();
- ICS.Ambiguous.setFromType(From->getType());
- ICS.Ambiguous.setToType(ToType);
- for (OverloadCandidateSet::iterator Cand = Conversions.begin();
- Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
- ICS.Ambiguous.addConversion(Cand->Function);
- } else {
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- }
-
- return ICS;
+ return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ AllowExplicit, InOverloadResolution, CStyle,
+ AllowObjCWritebackConversion);
}
ImplicitConversionSequence
@@ -2612,6 +2630,18 @@
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
+
+ Expr **Args = &From;
+ unsigned NumArgs = 1;
+ bool ListInitializing = false;
+ // If we're list-initializing, we pass the individual elements as
+ // arguments, not the entire list.
+ if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
+ Args = InitList->getInits();
+ NumArgs = InitList->getNumInits();
+ ListInitializing = true;
+ }
+
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
Con != ConEnd; ++Con) {
@@ -2628,28 +2658,33 @@
else
Constructor = cast<CXXConstructorDecl>(D);
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ bool Usable = !Constructor->isInvalidDecl();
+ if (ListInitializing)
+ Usable = Usable && (AllowExplicit || !Constructor->isExplicit());
+ else
+ Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit);
+ if (Usable) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- &From, 1, CandidateSet,
+ Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/
- !ConstructorsOnly);
+ !ConstructorsOnly &&
+ !ListInitializing);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
S.AddOverloadCandidate(Constructor, FoundDecl,
- &From, 1, CandidateSet,
+ Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/
- !ConstructorsOnly);
+ !ConstructorsOnly && !ListInitializing);
}
}
}
}
// Enumerate conversion functions, if we're allowed to.
- if (ConstructorsOnly) {
+ if (ConstructorsOnly || isa<InitListExpr>(From)) {
} else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
S.PDiag(0) << From->getSourceRange())) {
// No conversion functions from incomplete types.
@@ -2705,11 +2740,16 @@
// the argument of the constructor.
//
QualType ThisType = Constructor->getThisType(S.Context);
- if (Best->Conversions[0].isEllipsis())
- User.EllipsisConversion = true;
- else {
- User.Before = Best->Conversions[0].Standard;
- User.EllipsisConversion = false;
+ if (isa<InitListExpr>(From)) {
+ // Initializer lists don't have conversions as such.
+ User.Before.setAsIdentityConversion();
+ } else {
+ if (Best->Conversions[0].isEllipsis())
+ User.EllipsisConversion = true;
+ else {
+ User.Before = Best->Conversions[0].Standard;
+ User.EllipsisConversion = false;
+ }
}
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
@@ -3916,7 +3956,7 @@
// conversion sequence is the worst conversion necessary to convert an
// element of the list to X.
// FIXME: Recognize std::initializer_list.
- // FIXME: Arrays don't make sense until we can deal with references.
+ // FIXME: Implement arrays.
if (ToType->isArrayType())
return Result;
@@ -3926,9 +3966,15 @@
// conversion sequence is a user-defined conversion sequence. If multiple
// constructors are viable but none is better than the others, the
// implicit conversion sequence is a user-defined conversion sequence.
- // FIXME: Implement this.
- if (ToType->isRecordType() && !ToType->isAggregateType())
+ if (ToType->isRecordType() && !ToType->isAggregateType()) {
+ // This function can deal with initializer lists.
+ Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ InOverloadResolution, /*CStyle=*/false,
+ AllowObjCWritebackConversion);
+ Result.setListInitializationSequence();
return Result;
+ }
// C++11 [over.ics.list]p4:
// Otherwise, if the parameter has an aggregate type which can be
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp?rev=147156&r1=147155&r2=147156&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Thu Dec 22 12:58:38 2011
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+struct one { char c[1]; };
+struct two { char c[2]; };
+
namespace objects {
struct X1 { X1(int); };
@@ -45,8 +48,8 @@
void takes_C(C);
takes_C({1, 1.0});
- //C c;
- //c[{1, 1.0}]; needs overloading
+ C c;
+ c[{1, 1.0}];
return {1, 1.0};
}
@@ -56,11 +59,23 @@
(void) new C{1, 1.0};
}
- struct B {
- B(C, int, C);
+ struct B { // expected-note 2 {{candidate constructor}}
+ B(C, int, C); // expected-note {{candidate constructor not viable: cannot convert initializer list argument to 'objects::C'}}
};
void nested_init() {
- //B b{{1, 1.0}, 2, {3, 4}}; needs overloading
+ B b1{{1, 1.0}, 2, {3, 4}};
+ B b2{{1, 1.0, 4}, 2, {3, 4}}; // expected-error {{no matching constructor for initialization of 'objects::B'}}
+ }
+
+ void overloaded_call() {
+ one ov1(B); // expected-note {{not viable: cannot convert initializer list}}
+ two ov1(C); // expected-note {{not viable: cannot convert initializer list}}
+
+ static_assert(sizeof(ov1({})) == sizeof(two), "bad overload");
+ static_assert(sizeof(ov1({1, 2})) == sizeof(two), "bad overload");
+ static_assert(sizeof(ov1({{1, 1.0}, 2, {3, 4}})) == sizeof(one), "bad overload");
+
+ ov1({1}); // expected-error {{no matching function}}
}
}
More information about the cfe-commits
mailing list