def err_bad_cxx_cast_generic : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast}0 from %1 to %2 is not allowed">;
+def err_bad_cxx_cast_unrelated_class : Error<
+ "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+ "functional-style cast}0 from %1 to %2, which are not related by "
+ "inheritance, is not allowed">;
+def note_type_incomplete : Note<"%0 is incomplete">;
def err_bad_cxx_cast_rvalue : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast}0 from rvalue to reference type %2">;
S.Diag(opRange.getBegin(), msg) << castType
<< src->getType() << destType << opRange << src->getSourceRange();
+
+ // Detect if both types are (ptr to) class, and note any incompleteness.
+ int DifferentPtrness = 0;
+ QualType From = destType;
+ if (auto Ptr = From->getAs<PointerType>()) {
+ From = Ptr->getPointeeType();
+ DifferentPtrness++;
+ }
+ QualType To = src->getType();
+ if (auto Ptr = To->getAs<PointerType>()) {
+ To = Ptr->getPointeeType();
+ DifferentPtrness--;
+ }
+ if (!DifferentPtrness) {
+ auto RecFrom = From->getAs<RecordType>();
+ auto RecTo = To->getAs<RecordType>();
+ if (RecFrom && RecTo) {
+ auto DeclFrom = RecFrom->getAsCXXRecordDecl();
+ if (!DeclFrom->isCompleteDefinition())
+ S.Diag(DeclFrom->getLocation(), diag::note_type_incomplete)
+ << DeclFrom->getDeclName();
+ auto DeclTo = RecTo->getAsCXXRecordDecl();
+ if (!DeclTo->isCompleteDefinition())
+ S.Diag(DeclTo->getLocation(), diag::note_type_incomplete)
+ << DeclTo->getDeclName();
+ }
+ }
}
/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes,
if (!CStyle &&
Self.CheckTollFreeBridgeStaticCast(DestType, SrcExpr.get(), Kind))
return TC_Success;
+
+ // See if it looks like the user is trying to convert between
+ // related record types, and select a better diagnostic if so.
+ if (auto SrcPointer = SrcType->getAs<PointerType>())
+ if (auto DestPointer = DestType->getAs<PointerType>())
+ if (SrcPointer->getPointeeType()->getAs<RecordType>() &&
+ DestPointer->getPointeeType()->getAs<RecordType>())
+ msg = diag::err_bad_cxx_cast_unrelated_class;
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
struct G1 : public B {};
struct G2 : public B {};
struct H : public G1, public G2 {}; // Ambiguous path to B.
-struct I; // Incomplete.
-struct J; // Incomplete.
+struct I; // Incomplete. expected-note {{'I' is incomplete}}
+struct J; // Incomplete. expected-note {{'J' is incomplete}}
enum Enum { En1, En2 };
enum Onom { On1, On2 };
(void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast private base class 'A' to 'E'}}
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'A' to derived 'H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous cast from base 'A' to derived 'H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
- (void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'B *' to 'E *' is not allowed}}
+ (void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'B *' to 'E *', which are not related by inheritance, is not allowed}}
(void)static_cast<E&>(*((B*)0)); // expected-error {{non-const lvalue reference to type 'E' cannot bind to a value of unrelated type 'B'}}
+
+ (void)static_cast<E*>((J*)0); // expected-error {{static_cast from 'J *' to 'E *', which are not related by inheritance, is not allowed}}
+ (void)static_cast<I*>((B*)0); // expected-error {{static_cast from 'B *' to 'I *', which are not related by inheritance, is not allowed}}
+
// TODO: Test inaccessible base in context where it's accessible, i.e.
// member function and friend.