Tests for explicit conversion operators, along with a fix to avoid
considering explicit conversion operators when determining surrogate functions. Fixes PR10453. Note that there are a few test cases where Clang is still wrong because it does not implement DR899; see PR10456. Patch by Jonathan Sauer! llvm-svn: 135857
This commit is contained in:
parent
57132e88b7
commit
38b2d3fa3e
|
@ -9384,8 +9384,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
|
|||
}
|
||||
|
||||
// C++ [over.call.object]p2:
|
||||
// In addition, for each conversion function declared in T of the
|
||||
// form
|
||||
// In addition, for each (non-explicit in C++0x) conversion function
|
||||
// declared in T of the form
|
||||
//
|
||||
// operator conversion-type-id () cv-qualifier;
|
||||
//
|
||||
|
@ -9415,16 +9415,19 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
|
|||
continue;
|
||||
|
||||
CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
|
||||
if (!Conv->isExplicit()) {
|
||||
// Strip the reference type (if any) and then the pointer type (if
|
||||
// any) to get down to what might be a function type.
|
||||
QualType ConvType = Conv->getConversionType().getNonReferenceType();
|
||||
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
|
||||
ConvType = ConvPtrType->getPointeeType();
|
||||
|
||||
// Strip the reference type (if any) and then the pointer type (if
|
||||
// any) to get down to what might be a function type.
|
||||
QualType ConvType = Conv->getConversionType().getNonReferenceType();
|
||||
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
|
||||
ConvType = ConvPtrType->getPointeeType();
|
||||
|
||||
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
|
||||
AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
|
||||
Object.get(), Args, NumArgs, CandidateSet);
|
||||
if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>())
|
||||
{
|
||||
AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto,
|
||||
Object.get(), Args, NumArgs, CandidateSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform overload resolution.
|
||||
|
|
|
@ -36,4 +36,144 @@ namespace Conversion {
|
|||
void f(A a, B b) {
|
||||
b.f(a);
|
||||
}
|
||||
|
||||
void testExplicit()
|
||||
{
|
||||
// Taken from 12.3.2p2
|
||||
class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
|
||||
expected-note {{andidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
struct Z {
|
||||
explicit operator Y() const;
|
||||
explicit operator int() const;
|
||||
};
|
||||
|
||||
Z z;
|
||||
// 13.3.1.4p1 & 8.5p16:
|
||||
Y y2 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
// FIXME: These are well-formed per C++0x 13.3.1.4p1 (see DR899).
|
||||
Y y3 = (Y)z; // expected-error {{no matching conversion for C-style cast from 'Conversion::Z' to 'Conversion::Y''}}
|
||||
Y y4 = Y(z); // expected-error {{no matching conversion for functional-style cast from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
Y y5 = static_cast<Y>(z); // expected-error {{no matching conversion for static_cast from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
// 13.3.1.5p1 & 8.5p16:
|
||||
int i1 = (int)z;
|
||||
int i2 = int(z);
|
||||
int i3 = static_cast<int>(z);
|
||||
int i4(z);
|
||||
// 13.3.1.6p1 & 8.5.3p5:
|
||||
const Y& y6 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'const Conversion::Y'}}
|
||||
const int& y7(z);
|
||||
}
|
||||
|
||||
void testBool() {
|
||||
struct Bool {
|
||||
operator bool();
|
||||
};
|
||||
|
||||
struct NotBool {
|
||||
explicit operator bool(); // expected-note {{conversion to integral type 'bool'}}
|
||||
};
|
||||
Bool b;
|
||||
NotBool n;
|
||||
|
||||
(void) (1 + b);
|
||||
(void) (1 + n); // expected-error {{invalid operands to binary expression ('int' and 'Conversion::NotBool')}}
|
||||
|
||||
// 5.3.1p9:
|
||||
(void) (!b);
|
||||
(void) (!n);
|
||||
|
||||
// 5.14p1:
|
||||
(void) (b && true);
|
||||
(void) (n && true);
|
||||
|
||||
// 5.15p1:
|
||||
(void) (b || true);
|
||||
(void) (n || true);
|
||||
|
||||
// 5.16p1:
|
||||
(void) (b ? 0 : 1);
|
||||
(void) (n ? 0: 1);
|
||||
|
||||
// 5.19p5:
|
||||
// TODO: After constexpr has been implemented
|
||||
|
||||
// 6.4p4:
|
||||
if (b) {}
|
||||
if (n) {}
|
||||
|
||||
// 6.4.2p2:
|
||||
switch (b) {} // expected-warning {{switch condition has boolean value}}
|
||||
switch (n) {} // expected-error {{switch condition type 'Conversion::NotBool' requires explicit conversion to 'bool'}} \
|
||||
expected-warning {{switch condition has boolean value}}
|
||||
|
||||
// 6.5.1:
|
||||
while (b) {}
|
||||
while (n) {}
|
||||
|
||||
// 6.5.2p1:
|
||||
do {} while (b);
|
||||
do {} while (n);
|
||||
|
||||
// 6.5.3:
|
||||
for (;b;) {}
|
||||
for (;n;) {}
|
||||
}
|
||||
|
||||
void testNew()
|
||||
{
|
||||
// 5.3.4p6:
|
||||
struct Int {
|
||||
operator int();
|
||||
};
|
||||
struct NotInt {
|
||||
explicit operator int(); // expected-note {{conversion to integral type 'int' declared here}}
|
||||
};
|
||||
|
||||
Int i;
|
||||
NotInt ni;
|
||||
|
||||
new int[i];
|
||||
new int[ni]; // expected-error {{array size expression of type 'Conversion::NotInt' requires explicit conversion to type 'int'}}
|
||||
}
|
||||
|
||||
void testDelete()
|
||||
{
|
||||
// 5.3.5pp2:
|
||||
struct Ptr {
|
||||
operator int*();
|
||||
};
|
||||
struct NotPtr {
|
||||
explicit operator int*();
|
||||
};
|
||||
|
||||
Ptr p;
|
||||
NotPtr np;
|
||||
|
||||
delete p;
|
||||
delete np; // expected-error {{cannot delete expression of type 'Conversion::NotPtr'}}
|
||||
}
|
||||
|
||||
void testFunctionPointer()
|
||||
{
|
||||
// 13.3.1.1.2p2:
|
||||
using Func = void(*)(int);
|
||||
|
||||
struct FP {
|
||||
operator Func();
|
||||
};
|
||||
struct NotFP {
|
||||
explicit operator Func();
|
||||
};
|
||||
|
||||
FP fp;
|
||||
NotFP nfp;
|
||||
fp(1);
|
||||
nfp(1); // expected-error {{type 'Conversion::NotFP' does not provide a call operator}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue