forked from OSchip/llvm-project
PR 17456
More helpful diagnostic on casts between unrelated class hierarchies. llvm-svn: 227371
This commit is contained in:
parent
949389c395
commit
ffa7dc379f
|
@ -5267,6 +5267,11 @@ def err_bad_cstyle_cast_overload : Error<
|
||||||
def err_bad_cxx_cast_generic : Error<
|
def err_bad_cxx_cast_generic : Error<
|
||||||
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
|
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
|
||||||
"functional-style cast}0 from %1 to %2 is not allowed">;
|
"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<
|
def err_bad_cxx_cast_rvalue : Error<
|
||||||
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
|
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
|
||||||
"functional-style cast}0 from rvalue to reference type %2">;
|
"functional-style cast}0 from rvalue to reference type %2">;
|
||||||
|
|
|
@ -389,6 +389,33 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
|
||||||
|
|
||||||
S.Diag(opRange.getBegin(), msg) << castType
|
S.Diag(opRange.getBegin(), msg) << castType
|
||||||
<< src->getType() << destType << opRange << src->getSourceRange();
|
<< 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,
|
/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes,
|
||||||
|
@ -1079,6 +1106,14 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
|
||||||
if (!CStyle &&
|
if (!CStyle &&
|
||||||
Self.CheckTollFreeBridgeStaticCast(DestType, SrcExpr.get(), Kind))
|
Self.CheckTollFreeBridgeStaticCast(DestType, SrcExpr.get(), Kind))
|
||||||
return TC_Success;
|
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! :-(
|
// We tried everything. Everything! Nothing works! :-(
|
||||||
return TC_NotApplicable;
|
return TC_NotApplicable;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
|
// 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;
|
template<int I> struct Y;
|
||||||
|
|
||||||
X<X<int>> *x1;
|
X<X<int>> *x1;
|
||||||
|
|
|
@ -9,8 +9,8 @@ struct F : public C1 {}; // Single path to B with virtual.
|
||||||
struct G1 : public B {};
|
struct G1 : public B {};
|
||||||
struct G2 : public B {};
|
struct G2 : public B {};
|
||||||
struct H : public G1, public G2 {}; // Ambiguous path to B.
|
struct H : public G1, public G2 {}; // Ambiguous path to B.
|
||||||
struct I; // Incomplete.
|
struct I; // Incomplete. expected-note {{'I' is incomplete}}
|
||||||
struct J; // Incomplete.
|
struct J; // Incomplete. expected-note {{'J' is incomplete}}
|
||||||
|
|
||||||
enum Enum { En1, En2 };
|
enum Enum { En1, En2 };
|
||||||
enum Onom { On1, On2 };
|
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<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<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&>(*((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.
|
// TODO: Test inaccessible base in context where it's accessible, i.e.
|
||||||
// member function and friend.
|
// member function and friend.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue