This patch addresses 17456, which is a desire for failed casts involving
classes to give better diagnostic. see http://llvm.org/bugs/show_bug.cgi?id=17456
Rather than a plain 'cannot cast' error, this patch changes things to:
1) for static cast from 'A *' to 'B *' where T & S are classes, give
'static_cast from 'A *' to unrelated type 'B *' is not allowed'
2) where a cast fails and involves incomplete classes (directly or as a
pointer), it also notes that the class is incomplete. For instance:
17456.cc:6:10: error: static_cast from 'A *' to unrelated type 'B *' is not
allowed
return static_cast<B*>(arg);
^~~~~~~~~~~~~~~~~~~~
17456.cc:3:8: note: 'B' is incomplete
struct B;
The test suite already had applicable cases, so this patch just adjusts those
tests.
Perhaps the incomplete note should be broken out into a general utility
function? And perhaps unconditionally show the location of the class
definition/declaration, as that's probably useful in figuring out how to fix the
problem?
guidance welcome.
nathan
Index: tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- tools/clang/include/clang/Basic/DiagnosticSemaKinds.td (revision 222963)
+++ tools/clang/include/clang/Basic/DiagnosticSemaKinds.td (working copy)
@@ -5247,6 +5247,10 @@ def err_bad_cstyle_cast_overload : Error
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 : Error<
+ "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+ "functional-style cast}0 from %1 to unrelated type %2 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">;
Index: tools/clang/lib/Sema/SemaCast.cpp
===================================================================
--- tools/clang/lib/Sema/SemaCast.cpp (revision 222963)
+++ tools/clang/lib/Sema/SemaCast.cpp (working copy)
@@ -386,11 +386,34 @@ static void diagnoseBadCast(Sema &S, uns
bool listInitialization) {
if (msg == diag::err_bad_cxx_cast_generic &&
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType,
- listInitialization))
+ listInitialization))
return;
S.Diag(opRange.getBegin(), msg) << castType
<< src->getType() << destType << opRange << src->getSourceRange();
+
+ // Detect if types are incomplete, and note it.
+ QualType type = destType;
+ if (const PointerType *ptr = type->getAs<PointerType> ())
+ type = ptr->getPointeeType ();
+ if (const RecordType *rec = type->getAs<RecordType> ())
+ {
+ const CXXRecordDecl *decl = rec->getAsCXXRecordDecl ();
+ if (!decl->isCompleteDefinition ())
+ S.Diag (decl->getLocation (), diag::note_type_incomplete)
+ << decl->getDeclName ();
+ }
+
+ type = src->getType();
+ if (const PointerType *ptr = type->getAs<PointerType> ())
+ type = ptr->getPointeeType ();
+ if (const RecordType *rec = type->getAs<RecordType> ())
+ {
+ const CXXRecordDecl *decl = rec->getAsCXXRecordDecl ();
+ if (!decl->isCompleteDefinition ())
+ S.Diag (decl->getLocation (), diag::note_type_incomplete)
+ << decl->getDeclName ();
+ }
}
/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes,
@@ -1089,6 +1112,14 @@ static TryCastResult TryStaticCast(Sema
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 (const PointerType *SrcPointer = SrcType->getAs<PointerType>())
+ if (const PointerType *DestPointer = DestType->getAs<PointerType>())
+ if (SrcPointer->getPointeeType()->getAs<RecordType>()
+ && DestPointer->getPointeeType()->getAs<RecordType>())
+ msg = diag::err_bad_cxx_cast_unrelated;
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
Index: tools/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
===================================================================
--- tools/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp (revision 222963)
+++ tools/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp (working copy)
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
-template<typename T> struct X;
+template<typename T> struct X; // expected-note {{'X' is incomplete}}
template<int I> struct Y;
X<X<int>> *x1;
Index: tools/clang/test/SemaCXX/static-cast.cpp
===================================================================
--- tools/clang/test/SemaCXX/static-cast.cpp (revision 222963)
+++ tools/clang/test/SemaCXX/static-cast.cpp (working copy)
@@ -9,8 +9,8 @@ struct F : public C1 {}; // S
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 };
@@ -92,9 +92,13 @@ void t_529_5_8()
(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 unrelated type 'E *' 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 unrelated type 'E *' is not allowed}}
+ (void)static_cast<I*>((B*)0); // expected-error {{static_cast from 'B *' to unrelated type 'I *' is not allowed}}
+
// TODO: Test inaccessible base in context where it's accessible, i.e.
// member function and friend.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits