r191150 - PR17295: Do not allow explicit conversion functions to be used in cases where
Richard Smith
richard-llvm at metafoo.co.uk
Sat Sep 21 14:55:46 PDT 2013
Author: rsmith
Date: Sat Sep 21 16:55:46 2013
New Revision: 191150
URL: http://llvm.org/viewvc/llvm-project?rev=191150&view=rev
Log:
PR17295: Do not allow explicit conversion functions to be used in cases where
an additional conversion (other than a qualification conversion) would be
required after the explicit conversion.
Conversely, do allow explicit conversion functions to be used when initializing
a temporary for a reference binding in direct-list-initialization.
Modified:
cfe/trunk/include/clang/Sema/Initialization.h
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/SemaCXX/explicit.cpp
Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=191150&r1=191149&r2=191150&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Sat Sep 21 16:55:46 2013
@@ -853,6 +853,10 @@ public:
const InitializationKind &Kind,
MultiExprArg Args,
bool InInitList = false);
+ void InitializeFrom(Sema &S, const InitializedEntity &Entity,
+ const InitializationKind &Kind, MultiExprArg Args,
+ bool InInitList);
+
~InitializationSequence();
/// \brief Perform the actual initialization of the given entity based on
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=191150&r1=191149&r2=191150&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Sat Sep 21 16:55:46 2013
@@ -3346,6 +3346,33 @@ static void TryListInitialization(Sema &
return;
}
}
+ if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
+ InitList->getNumInits() == 1 &&
+ InitList->getInit(0)->getType()->isRecordType()) {
+ // - Otherwise, if the initializer list has a single element of type E
+ // [...references are handled above...], the object or reference is
+ // initialized from that element; if a narrowing conversion is required
+ // to convert the element to T, the program is ill-formed.
+ //
+ // Per core-24034, this is direct-initialization if we were performing
+ // direct-list-initialization and copy-initialization otherwise.
+ // We can't use InitListChecker for this, because it always performs
+ // copy-initialization. This only matters if we might use an 'explicit'
+ // conversion operator, so we only need to handle the cases where the source
+ // is of record type.
+ InitializationKind SubKind =
+ Kind.getKind() == InitializationKind::IK_DirectList
+ ? InitializationKind::CreateDirect(Kind.getLocation(),
+ InitList->getLBraceLoc(),
+ InitList->getRBraceLoc())
+ : Kind;
+ Expr *SubInit[1] = { InitList->getInit(0) };
+ Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
+ /*TopLevelOfInitList*/true);
+ if (Sequence)
+ Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+ return;
+ }
InitListChecker CheckInitList(S, Entity, InitList,
DestType, /*VerifyOnly=*/true);
@@ -4366,6 +4393,14 @@ InitializationSequence::InitializationSe
MultiExprArg Args,
bool TopLevelOfInitList)
: FailedCandidateSet(Kind.getLocation()) {
+ InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
+}
+
+void InitializationSequence::InitializeFrom(Sema &S,
+ const InitializedEntity &Entity,
+ const InitializationKind &Kind,
+ MultiExprArg Args,
+ bool TopLevelOfInitList) {
ASTContext &Context = S.Context;
// Eliminate non-overload placeholder types in the arguments. We
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=191150&r1=191149&r2=191150&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Sep 21 16:55:46 2013
@@ -5829,6 +5829,17 @@ Sema::AddConversionCandidate(CXXConversi
ConvType = Conversion->getConversionType().getNonReferenceType();
}
+ // Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
+ // operator is only a candidate if its return type is the target type or
+ // can be converted to the target type with a qualification conversion.
+ bool ObjCLifetimeConversion;
+ QualType ToNonRefType = ToType.getNonReferenceType();
+ if (Conversion->isExplicit() &&
+ !Context.hasSameUnqualifiedType(ConvType, ToNonRefType) &&
+ !IsQualificationConversion(ConvType, ToNonRefType, /*CStyle*/false,
+ ObjCLifetimeConversion))
+ return;
+
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=191150&r1=191149&r2=191150&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sat Sep 21 16:55:46 2013
@@ -3372,7 +3372,9 @@ void Sema::BuildVariableInstantiation(
OldVar->isPreviousDeclInSameBlockScope());
NewVar->setAccess(OldVar->getAccess());
- if (!OldVar->isStaticDataMember()) {
+ // For local variables, inherit the 'used' and 'referenced' flags from the
+ // primary template.
+ if (OldVar->getLexicalDeclContext()->isFunctionOrMethod()) {
NewVar->setIsUsed(OldVar->isUsed(false));
NewVar->setReferenced(OldVar->isReferenced());
}
Modified: cfe/trunk/test/SemaCXX/explicit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/explicit.cpp?rev=191150&r1=191149&r2=191150&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/explicit.cpp (original)
+++ cfe/trunk/test/SemaCXX/explicit.cpp Sat Sep 21 16:55:46 2013
@@ -4,11 +4,11 @@ struct A {
A(int);
};
-struct B {
+struct B { // expected-note+ {{candidate}}
explicit B(int);
};
-B::B(int) { }
+B::B(int) { } // expected-note+ {{here}}
struct C {
void f(const A&);
@@ -18,6 +18,22 @@ struct C {
void f(C c) {
c.f(10);
}
+
+A a0 = 0;
+A a1(0);
+A &&a2 = 0;
+A &&a3(0);
+A a4{0};
+A &&a5 = {0};
+A &&a6{0};
+
+B b0 = 0; // expected-error {{no viable conversion}}
+B b1(0);
+B &&b2 = 0; // expected-error {{could not bind}}
+B &&b3(0); // expected-error {{could not bind}}
+B b4{0};
+B &&b5 = {0}; // expected-error {{chosen constructor is explicit}}
+B &&b6{0};
}
namespace Conversion {
@@ -40,12 +56,11 @@ namespace Conversion {
void testExplicit()
{
// Taken from 12.3.2p2
- class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Z' to 'const Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Z' to 'Y &&' for 1st argument}} \
- expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Z' to 'const Y &' for 1st argument}} \
- expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Z' to 'Y &&' for 1st argument}}
+ class X { X(); }; // expected-note+ {{candidate constructor}}
+ class Y { }; // expected-note+ {{candidate constructor (the implicit}}
struct Z {
+ explicit operator X() const;
explicit operator Y() const;
explicit operator int() const;
};
@@ -53,6 +68,7 @@ namespace Conversion {
Z z;
// 13.3.1.4p1 & 8.5p16:
Y y2 = z; // expected-error {{no viable conversion from 'Z' to 'Y'}}
+ Y y2b(z);
Y y3 = (Y)z;
Y y4 = Y(z);
Y y5 = static_cast<Y>(z);
@@ -63,7 +79,24 @@ namespace Conversion {
int i4(z);
// 13.3.1.6p1 & 8.5.3p5:
const Y& y6 = z; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
- const int& y7(z);
+ const int& y7 = z; // expected-error {{no viable conversion from 'Z' to 'const int'}}
+ const Y& y8(z);
+ const int& y9(z);
+
+ // Y is an aggregate, so aggregate-initialization is performed and the
+ // conversion function is not considered.
+ const Y y10{z}; // expected-error {{excess elements}}
+ const Y& y11{z}; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
+ const int& y12{z};
+
+ // X is not an aggregate, so constructors are considered.
+ // However, by 13.3.3.1/4, only standard conversion sequences and
+ // ellipsis conversion sequences are considered here, so this is not
+ // allowed.
+ // FIXME: It's not really clear that this is a sensible restriction for this
+ // case. g++ allows this, EDG does not.
+ const X x1{z}; // expected-error {{no matching constructor}}
+ const X& x2{z}; // expected-error {{no matching constructor}}
}
void testBool() {
@@ -119,6 +152,40 @@ namespace Conversion {
// 6.5.3:
for (;b;) {}
for (;n;) {}
+
+ // 13.3.1.5p1:
+ bool direct1(b);
+ bool direct2(n);
+ int direct3(b);
+ int direct4(n); // expected-error {{no viable conversion}}
+ const bool &direct5(b);
+ const bool &direct6(n);
+ const int &direct7(b);
+ const int &direct8(n); // expected-error {{no viable conversion}}
+ bool directList1{b};
+ bool directList2{n};
+ int directList3{b};
+ int directList4{n}; // expected-error {{no viable conversion}}
+ const bool &directList5{b};
+ const bool &directList6{n};
+ const int &directList7{b};
+ const int &directList8{n}; // expected-error {{no viable conversion}}
+ bool copy1 = b;
+ bool copy2 = n; // expected-error {{no viable conversion}}
+ int copy3 = b;
+ int copy4 = n; // expected-error {{no viable conversion}}
+ const bool ©5 = b;
+ const bool ©6 = n; // expected-error {{no viable conversion}}
+ const int ©7 = b;
+ const int ©8 = n; // expected-error {{no viable conversion}}
+ bool copyList1 = {b};
+ bool copyList2 = {n}; // expected-error {{no viable conversion}}
+ int copyList3 = {b};
+ int copyList4 = {n}; // expected-error {{no viable conversion}}
+ const bool ©List5 = {b};
+ const bool ©List6 = {n}; // expected-error {{no viable conversion}}
+ const int ©List7 = {b};
+ const int ©List8 = {n}; // expected-error {{no viable conversion}}
}
void testNew()
More information about the cfe-commits
mailing list