aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-02-14 18:34:10 +0000
committerJohn McCall <rjmccall@apple.com>2011-02-14 18:34:10 +0000
commit79ab2c8104ef5df233d271560ccc734836738e56 (patch)
treeae88d2d76339b8b0edba2efa52cd107d1b6be47e
parente69b09955acbde87470eea8bc99b580195569dc0 (diff)
Provide overload diagnostics when explicit casts involving class types fail.
PR8626. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125506 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td11
-rw-r--r--include/clang/Sema/Initialization.h8
-rw-r--r--lib/Sema/SemaCXXCast.cpp112
-rw-r--r--test/CXX/special/class.copy/p9.cpp24
-rw-r--r--test/SemaCXX/cast-conversion.cpp10
-rw-r--r--test/SemaCXX/vector-casts.cpp6
-rw-r--r--test/SemaObjCXX/cstyle-cast.mm2
-rw-r--r--test/SemaTemplate/instantiate-cast.cpp8
8 files changed, 140 insertions, 41 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2cca767360..82ebf0b56d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index a8ab472427..c191565990 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -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;
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index afbfa17e77..dda7f67d3f 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -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)
diff --git a/test/CXX/special/class.copy/p9.cpp b/test/CXX/special/class.copy/p9.cpp
index 494b12fd79..77ab19e210 100644
--- a/test/CXX/special/class.copy/p9.cpp
+++ b/test/CXX/special/class.copy/p9.cpp
@@ -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'}}
}
diff --git a/test/SemaCXX/cast-conversion.cpp b/test/SemaCXX/cast-conversion.cpp
index d68e789c37..80707d13d2 100644
--- a/test/SemaCXX/cast-conversion.cpp
+++ b/test/SemaCXX/cast-conversion.cpp
@@ -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}}
}
diff --git a/test/SemaCXX/vector-casts.cpp b/test/SemaCXX/vector-casts.cpp
index 4bb5808439..681a07ea47 100644
--- a/test/SemaCXX/vector-casts.cpp
+++ b/test/SemaCXX/vector-casts.cpp
@@ -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}}
diff --git a/test/SemaObjCXX/cstyle-cast.mm b/test/SemaObjCXX/cstyle-cast.mm
index c4b176c975..29a8404660 100644
--- a/test/SemaObjCXX/cstyle-cast.mm
+++ b/test/SemaObjCXX/cstyle-cast.mm
@@ -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;
diff --git a/test/SemaTemplate/instantiate-cast.cpp b/test/SemaTemplate/instantiate-cast.cpp
index 9669b2035a..abf1b3c31d 100644
--- a/test/SemaTemplate/instantiate-cast.cpp
+++ b/test/SemaTemplate/instantiate-cast.cpp
@@ -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}}
}
};