forked from OSchip/llvm-project
Provide overload diagnostics when explicit casts involving class types fail.
PR8626. llvm-svn: 125506
This commit is contained in:
parent
dd68bd0a65
commit
909acf8209
|
@ -1414,6 +1414,17 @@ def note_ovl_builtin_unary_candidate : Note<
|
|||
"built-in candidate %0">;
|
||||
def err_ovl_no_viable_function_in_init : Error<
|
||||
"no matching constructor for initialization of %0">;
|
||||
def err_ovl_no_conversion_in_cast : Error<
|
||||
"cannot convert %1 to %2 without a conversion operator">;
|
||||
def err_ovl_no_viable_conversion_in_cast : Error<
|
||||
"no matching conversion for %select{|static_cast|reinterpret_cast|"
|
||||
"dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">;
|
||||
def err_ovl_ambiguous_conversion_in_cast : Error<
|
||||
"ambiguous conversion for %select{|static_cast|reinterpret_cast|"
|
||||
"dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">;
|
||||
def err_ovl_deleted_conversion_in_cast : Error<
|
||||
"%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
|
||||
"functional-style cast}0 from %1 to %2 uses deleted function">;
|
||||
def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">;
|
||||
def err_ref_init_ambiguous : Error<
|
||||
"reference initialization of type %0 with initializer of type %1 is ambiguous">;
|
||||
|
|
|
@ -791,12 +791,18 @@ public:
|
|||
return FailedCandidateSet;
|
||||
}
|
||||
|
||||
/// brief Get the overloading result, for when the initialization
|
||||
/// sequence failed due to a bad overload.
|
||||
OverloadingResult getFailedOverloadResult() const {
|
||||
return FailedOverloadResult;
|
||||
}
|
||||
|
||||
/// \brief Determine why initialization failed.
|
||||
FailureKind getFailureKind() const {
|
||||
assert(getKind() == FailedSequence && "Not an initialization failure!");
|
||||
return Failure;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Dump a representation of this initialization sequence to
|
||||
/// the given stream, for debugging purposes.
|
||||
void dump(llvm::raw_ostream &OS) const;
|
||||
|
|
|
@ -214,6 +214,92 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
/// Try to diagnose a failed overloaded cast. Returns true if
|
||||
/// diagnostics were emitted.
|
||||
static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
|
||||
SourceRange range, Expr *src,
|
||||
QualType destType) {
|
||||
switch (CT) {
|
||||
// These cast kinds don't consider user-defined conversions.
|
||||
case CT_Const:
|
||||
case CT_Reinterpret:
|
||||
case CT_Dynamic:
|
||||
return false;
|
||||
|
||||
// These do.
|
||||
case CT_Static:
|
||||
case CT_CStyle:
|
||||
case CT_Functional:
|
||||
break;
|
||||
}
|
||||
|
||||
QualType srcType = src->getType();
|
||||
if (!destType->isRecordType() && !srcType->isRecordType())
|
||||
return false;
|
||||
|
||||
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
|
||||
InitializationKind initKind
|
||||
= InitializationKind::CreateCast(/*type range?*/ range,
|
||||
(CT == CT_CStyle || CT == CT_Functional));
|
||||
InitializationSequence sequence(S, entity, initKind, &src, 1);
|
||||
|
||||
assert(sequence.getKind() == InitializationSequence::FailedSequence &&
|
||||
"initialization succeeded on second try?");
|
||||
switch (sequence.getFailureKind()) {
|
||||
default: return false;
|
||||
|
||||
case InitializationSequence::FK_ConstructorOverloadFailed:
|
||||
case InitializationSequence::FK_UserConversionOverloadFailed:
|
||||
break;
|
||||
}
|
||||
|
||||
OverloadCandidateSet &candidates = sequence.getFailedCandidateSet();
|
||||
|
||||
unsigned msg = 0;
|
||||
OverloadCandidateDisplayKind howManyCandidates = OCD_AllCandidates;
|
||||
|
||||
switch (sequence.getFailedOverloadResult()) {
|
||||
case OR_Success: llvm_unreachable("successful failed overload");
|
||||
return false;
|
||||
case OR_No_Viable_Function:
|
||||
if (candidates.empty())
|
||||
msg = diag::err_ovl_no_conversion_in_cast;
|
||||
else
|
||||
msg = diag::err_ovl_no_viable_conversion_in_cast;
|
||||
howManyCandidates = OCD_AllCandidates;
|
||||
break;
|
||||
|
||||
case OR_Ambiguous:
|
||||
msg = diag::err_ovl_ambiguous_conversion_in_cast;
|
||||
howManyCandidates = OCD_ViableCandidates;
|
||||
break;
|
||||
|
||||
case OR_Deleted:
|
||||
msg = diag::err_ovl_deleted_conversion_in_cast;
|
||||
howManyCandidates = OCD_ViableCandidates;
|
||||
break;
|
||||
}
|
||||
|
||||
S.Diag(range.getBegin(), msg)
|
||||
<< CT << srcType << destType
|
||||
<< range << src->getSourceRange();
|
||||
|
||||
candidates.NoteCandidates(S, howManyCandidates, &src, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Diagnose a failed cast.
|
||||
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
|
||||
SourceRange opRange, Expr *src, QualType destType) {
|
||||
if (msg == diag::err_bad_cxx_cast_generic &&
|
||||
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType))
|
||||
return;
|
||||
|
||||
S.Diag(opRange.getBegin(), msg) << castType
|
||||
<< src->getType() << destType << opRange << src->getSourceRange();
|
||||
}
|
||||
|
||||
/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes,
|
||||
/// this removes one level of indirection from both types, provided that they're
|
||||
/// the same kind of pointer (plain or to-member). Unlike the Sema function,
|
||||
|
@ -492,20 +578,17 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
msg, Kind)
|
||||
!= TC_Success && msg != 0)
|
||||
{
|
||||
if (SrcExpr->getType() == Self.Context.OverloadTy)
|
||||
{
|
||||
if (SrcExpr->getType() == Self.Context.OverloadTy) {
|
||||
//FIXME: &f<int>; is overloaded and resolvable
|
||||
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload)
|
||||
<< OverloadExpr::find(SrcExpr).Expression->getName()
|
||||
<< DestType << OpRange;
|
||||
NoteAllOverloadCandidates(SrcExpr, Self);
|
||||
|
||||
} else {
|
||||
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType);
|
||||
}
|
||||
else
|
||||
Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret
|
||||
<< SrcExpr->getType() << DestType << OpRange;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -533,16 +616,14 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
|
|||
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
|
||||
Kind, BasePath) != TC_Success && msg != 0)
|
||||
{
|
||||
if (SrcExpr->getType() == Self.Context.OverloadTy)
|
||||
{
|
||||
if (SrcExpr->getType() == Self.Context.OverloadTy) {
|
||||
OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
|
||||
Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload)
|
||||
<< oe->getName() << DestType << OpRange << oe->getQualifierRange();
|
||||
NoteAllOverloadCandidates(SrcExpr, Self);
|
||||
} else {
|
||||
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType);
|
||||
}
|
||||
else
|
||||
Self.Diag(OpRange.getBegin(), msg) << CT_Static
|
||||
<< SrcExpr->getType() << DestType << OpRange;
|
||||
}
|
||||
else if (Kind == CK_BitCast)
|
||||
Self.CheckCastAlign(SrcExpr, DestType, OpRange);
|
||||
|
@ -1374,7 +1455,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
|||
// So we finish by allowing everything that remains - it's got to be two
|
||||
// object pointers.
|
||||
return TC_Success;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
|
||||
|
@ -1445,9 +1526,10 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
|
|||
Found);
|
||||
assert(!Fn && "cast failed but able to resolve overload expression!!");
|
||||
(void)Fn;
|
||||
|
||||
} else {
|
||||
Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle)
|
||||
<< CastExpr->getType() << CastTy << R;
|
||||
diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
|
||||
R, CastExpr, CastTy);
|
||||
}
|
||||
}
|
||||
else if (Kind == CK_BitCast)
|
||||
|
|
|
@ -15,30 +15,30 @@ struct VirtualInheritsNonConstCopy : virtual NonConstCopy {
|
|||
VirtualInheritsNonConstCopy(const VirtualInheritsNonConstCopy&);
|
||||
};
|
||||
|
||||
struct ImplicitNonConstCopy1 : NonConstCopy {
|
||||
ImplicitNonConstCopy1();
|
||||
struct ImplicitNonConstCopy1 : NonConstCopy { // expected-note {{candidate constructor}}
|
||||
ImplicitNonConstCopy1(); // expected-note {{candidate constructor}}
|
||||
};
|
||||
|
||||
struct ImplicitNonConstCopy2 {
|
||||
ImplicitNonConstCopy2();
|
||||
struct ImplicitNonConstCopy2 { // expected-note {{candidate constructor}}
|
||||
ImplicitNonConstCopy2(); // expected-note {{candidate constructor}}
|
||||
NonConstCopy ncc;
|
||||
};
|
||||
|
||||
struct ImplicitNonConstCopy3 {
|
||||
ImplicitNonConstCopy3();
|
||||
struct ImplicitNonConstCopy3 { // expected-note {{candidate constructor}}
|
||||
ImplicitNonConstCopy3(); // expected-note {{candidate constructor}}
|
||||
NonConstCopy ncc_array[2][3];
|
||||
};
|
||||
|
||||
struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy {
|
||||
ImplicitNonConstCopy4();
|
||||
struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy { // expected-note {{candidate constructor}}
|
||||
ImplicitNonConstCopy4(); // expected-note {{candidate constructor}}
|
||||
};
|
||||
|
||||
void test_non_const_copy(const ImplicitNonConstCopy1 &cincc1,
|
||||
const ImplicitNonConstCopy2 &cincc2,
|
||||
const ImplicitNonConstCopy3 &cincc3,
|
||||
const ImplicitNonConstCopy4 &cincc4) {
|
||||
(void)sizeof(ImplicitNonConstCopy1(cincc1)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy1' to 'ImplicitNonConstCopy1' is not allowed}}
|
||||
(void)sizeof(ImplicitNonConstCopy2(cincc2)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy2' to 'ImplicitNonConstCopy2' is not allowed}}
|
||||
(void)sizeof(ImplicitNonConstCopy3(cincc3)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy3' to 'ImplicitNonConstCopy3' is not allowed}}
|
||||
(void)sizeof(ImplicitNonConstCopy4(cincc4)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy4' to 'ImplicitNonConstCopy4' is not allowed}}
|
||||
(void)sizeof(ImplicitNonConstCopy1(cincc1)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy1' to 'ImplicitNonConstCopy1'}}
|
||||
(void)sizeof(ImplicitNonConstCopy2(cincc2)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy2' to 'ImplicitNonConstCopy2'}}
|
||||
(void)sizeof(ImplicitNonConstCopy3(cincc3)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy3' to 'ImplicitNonConstCopy3'}}
|
||||
(void)sizeof(ImplicitNonConstCopy4(cincc4)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy4' to 'ImplicitNonConstCopy4'}}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ struct A {
|
|||
A(R);
|
||||
};
|
||||
|
||||
struct B {
|
||||
B(A);
|
||||
struct B { // expected-note 3 {{candidate constructor (the implicit copy constructor) not viable}}
|
||||
B(A); // expected-note 3 {{candidate constructor not viable}}
|
||||
};
|
||||
|
||||
int main () {
|
||||
B(10); // expected-error {{functional-style cast from 'int' to 'B' is not allowed}}
|
||||
(B)10; // expected-error {{C-style cast from 'int' to 'B' is not allowed}}
|
||||
static_cast<B>(10); // expected-error {{static_cast from 'int' to 'B' is not allowed}} \\
|
||||
B(10); // expected-error {{no matching conversion for functional-style cast from 'int' to 'B'}}
|
||||
(B)10; // expected-error {{no matching conversion for C-style cast from 'int' to 'B'}}
|
||||
static_cast<B>(10); // expected-error {{no matching conversion for static_cast from 'int' to 'B'}} \\
|
||||
// expected-warning {{expression result unused}}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ typedef int __v2si __attribute__((__vector_size__(8)));
|
|||
typedef short __v4hi __attribute__((__vector_size__(8)));
|
||||
typedef short __v8hi __attribute__((__vector_size__(16)));
|
||||
|
||||
struct S { };
|
||||
struct S { }; // expected-note 2 {{candidate constructor}}
|
||||
|
||||
void f() {
|
||||
__v2si v2si;
|
||||
|
@ -23,9 +23,9 @@ void f() {
|
|||
(void)(__v2si)(ll);
|
||||
|
||||
(void)reinterpret_cast<S>(v2si); // expected-error {{reinterpret_cast from '__v2si' to 'S' is not allowed}}
|
||||
(void)(S)v2si; // expected-error {{C-style cast from '__v2si' to 'S' is not allowed}}
|
||||
(void)(S)v2si; // expected-error {{no matching conversion for C-style cast from '__v2si' to 'S'}}
|
||||
(void)reinterpret_cast<__v2si>(s); // expected-error {{reinterpret_cast from 'S' to '__v2si' is not allowed}}
|
||||
(void)(__v2si)s; // expected-error {{C-style cast from 'S' to '__v2si' is not allowed}}
|
||||
(void)(__v2si)s; // expected-error {{cannot convert 'S' to '__v2si' without a conversion operator}}
|
||||
|
||||
(void)reinterpret_cast<unsigned char>(v2si); // expected-error {{reinterpret_cast from vector '__v2si' to scalar 'unsigned char' of different size}}
|
||||
(void)(unsigned char)v2si; // expected-error {{C-style cast from vector '__v2si' to scalar 'unsigned char' of different size}}
|
||||
|
|
|
@ -18,7 +18,7 @@ void test1(X x) {
|
|||
|
||||
I<P> *ip = (I<P>*)cft;
|
||||
|
||||
(id)x; // expected-error {{C-style cast from 'X' to 'id' is not allowed}}
|
||||
(id)x; // expected-error {{cannot convert 'X' to 'id' without a conversion operator}}
|
||||
|
||||
id *pid = (id*)ccct;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
struct A { int x; };
|
||||
struct A { int x; }; // expected-note 2 {{candidate constructor}}
|
||||
|
||||
class Base {
|
||||
public:
|
||||
|
@ -23,7 +23,7 @@ struct Constructible {
|
|||
template<typename T, typename U>
|
||||
struct CStyleCast0 {
|
||||
void f(T t) {
|
||||
(void)((U)t); // expected-error{{C-style cast from 'A' to 'int' is not allowed}}
|
||||
(void)((U)t); // expected-error{{cannot convert 'A' to 'int' without a conversion operator}}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -36,7 +36,7 @@ template struct CStyleCast0<A, int>; // expected-note{{instantiation}}
|
|||
template<typename T, typename U>
|
||||
struct StaticCast0 {
|
||||
void f(T t) {
|
||||
(void)static_cast<U>(t); // expected-error{{static_cast from 'int' to 'A' is not allowed}}
|
||||
(void)static_cast<U>(t); // expected-error{{no matching conversion for static_cast from 'int' to 'A'}}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -89,7 +89,7 @@ template struct ConstCast0<int const *, float *>; // expected-note{{instantiatio
|
|||
template<typename T, typename U>
|
||||
struct FunctionalCast1 {
|
||||
void f(T t) {
|
||||
(void)U(t); // expected-error{{functional-style cast from 'A' to 'int' is not allowed}}
|
||||
(void)U(t); // expected-error{{cannot convert 'A' to 'int' without a conversion operator}}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue