Implement C++ semantics for C-style and functional-style casts. This regresses Clang extension conversions, like vectors, but allows conversions via constructors and conversion operators.

Add custom conversions to static_cast.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77076 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sebastian Redl 2009-07-25 15:41:38 +00:00
Родитель 10aebbb5c8
Коммит 9cc11e7003
12 изменённых файлов: 1109 добавлений и 742 удалений

Просмотреть файл

@ -1395,36 +1395,46 @@ def note_property_impl_required : Note<
// C++ casts
def err_bad_cxx_cast_generic : Error<"%0 from %2 to %1 is not allowed">;
def err_bad_cxx_cast_rvalue : Error<"%0 from rvalue to reference type %1">;
// These messages adhere to the TryCast pattern: %0 is an int specifying the
// cast type, %1 is the source type, %2 is the destination type.
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_rvalue : Error<
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast}0 from rvalue to reference type %2">;
def err_bad_cxx_cast_const_away : Error<
"%0 from %2 to %1 casts away constness">;
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
"functional-style cast}0 from %1 to %2 casts away constness">;
def err_bad_const_cast_dest : Error<
"const_cast to %0, which is not a reference, pointer-to-object, "
"or pointer-to-data-member">;
def err_bad_reinterpret_cast_same_type : Error<
"source and destination type of reinterpret_cast are not distinct">;
def ext_reinterpret_cast_fn_obj : Extension<
"reinterpret_cast between pointer-to-function and pointer-to-object is "
"an extension">;
"%select{const_cast||||C-style cast|functional-style cast}0 to %2, "
"which is not a reference, pointer-to-object, or pointer-to-data-member">;
def ext_cast_fn_obj : Extension<
"cast between pointer-to-function and pointer-to-object is an extension">;
def err_bad_reinterpret_cast_small_int : Error<
"cast from pointer to smaller type %0 loses information">;
"cast from pointer to smaller type %2 loses information">;
def err_bad_lvalue_to_rvalue_cast : Error<
"cannot cast from lvalue of type %1 to rvalue reference type %2; types are "
"not compatible">;
def err_bad_static_cast_pointer_nonpointer : Error<
"cannot cast from type %1 to pointer type %2">;
def err_bad_static_cast_member_pointer_nonmp : Error<
"cannot cast from type %1 to member pointer type %2">;
// These messages don't adhere to the pattern.
// FIXME: Display the path somehow better.
def err_ambiguous_base_to_derived_cast : Error<
"ambiguous cast from base %0 to derived %1:%2">;
def err_static_downcast_via_virtual : Error<
"cannot cast %0 to %1 via virtual base %2">;
def err_downcast_from_inaccessible_base : Error<
"cannot cast %1 to %0 due to inaccessible conversion path">;
def err_bad_dynamic_cast_not_ref_or_ptr : Error<
"%0 is not a reference or pointer">;
def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">;
def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">;
def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">;
def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">;
// FIXME: Display the path somehow better.
def err_ambiguous_base_to_derived_cast : Error<
"ambiguous static_cast from base %0 to derived %1:%2">;
def err_static_downcast_via_virtual : Error<
"cannot cast %0 to %1 via virtual base %2">;
def err_bad_lvalue_to_rvalue_cast : Error<
"cannot cast from lvalue of type %0 to rvalue reference to %1; types are "
"not compatible">;
// Other C++ expressions
def err_need_header_before_typeid : Error<

Просмотреть файл

@ -3169,9 +3169,10 @@ public:
bool AllowExplicit = false,
bool ForceRValue = false);
/// CheckCastTypes - Check type constraints for casting between types.
/// CheckCastTypes - Check type constraints for casting between types under
/// C semantics.
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size.
@ -3184,7 +3185,11 @@ public:
// or vectors and the element type of that vector.
// returns true if the cast is invalid
bool CheckExtVectorCast(SourceRange R, QualType VectorTy, QualType Ty);
/// CXXCheckCStyleCast - Check constraints of a C-style or function-style
/// cast under C++ semantics.
bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr);
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
/// \param [out] ReturnType - The return type of the send.
@ -3196,7 +3201,7 @@ public:
/// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid.
bool CheckCXXBooleanCondition(Expr *&CondExpr);
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// the specified width and sign. If an overflow occurs, detect it and emit
/// the specified diagnostic.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2919,14 +2919,15 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
/// CheckCastTypes - Check type constraints for casting between types.
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) {
if (getLangOptions().CPlusPlus)
return CXXCheckCStyleCast(TyR, castType, castExpr);
UsualUnaryConversions(castExpr);
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
if (castType->isVoidType()) {
// Cast to void allows any expr type.
} else if (castType->isDependentType() || castExpr->isTypeDependent()) {
// We can't check any more until template instantiation time.
} else if (!castType->isScalarType() && !castType->isVectorType()) {
if (Context.getCanonicalType(castType).getUnqualifiedType() ==
Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) &&
@ -3040,7 +3041,8 @@ Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr))
return ExprError();
return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType,
return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
castExpr, castType,
LParenLoc, RParenLoc));
}

Просмотреть файл

@ -1136,7 +1136,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// CheckPointerConversion - Check the pointer conversion from the
/// expression From to the type ToType. This routine checks for
/// ambiguous (FIXME: or inaccessible) derived-to-base pointer
/// ambiguous or inaccessible derived-to-base pointer
/// conversions for which IsPointerConversion has already returned
/// true. It returns true and produces a diagnostic if there was an
/// error, or returns false otherwise.

Просмотреть файл

@ -5,9 +5,9 @@ void f() {
int x, *px;
// Type id.
(T())x; // expected-error {{used type 'T ()'}}
(T())+x; // expected-error {{used type 'T ()'}}
(T())*px; // expected-error {{used type 'T ()'}}
(T())x; // expected-error {{cast from 'int' to 'T ()'}}
(T())+x; // expected-error {{cast from 'int' to 'T ()'}}
(T())*px; // expected-error {{cast from 'int' to 'T ()'}}
// Expression.
x = (T());

Просмотреть файл

@ -0,0 +1,231 @@
// RUN: clang-cc -fsyntax-only -verify -faccess-control %s
struct A {};
// ----------- const_cast --------------
typedef char c;
typedef c *cp;
typedef cp *cpp;
typedef cpp *cppp;
typedef cppp &cpppr;
typedef const cppp &cpppcr;
typedef const char cc;
typedef cc *ccp;
typedef volatile ccp ccvp;
typedef ccvp *ccvpp;
typedef const volatile ccvpp ccvpcvp;
typedef ccvpcvp *ccvpcvpp;
typedef int iar[100];
typedef iar &iarr;
typedef int (*f)(int);
void t_cc()
{
ccvpcvpp var = 0;
// Cast away deep consts and volatiles.
char ***var2 = (cppp)(var);
char ***const &var3 = var2;
// Const reference to reference.
char ***&var4 = (cpppr)(var3);
// Drop reference. Intentionally without qualifier change.
char *** var5 = (cppp)(var4);
const int ar[100] = {0};
// Array decay. Intentionally without qualifier change.
int *pi = (int*)(ar);
f fp = 0;
// Don't misidentify fn** as a function pointer.
f *fpp = (f*)(&fp);
int const A::* const A::*icapcap = 0;
int A::* A::* iapap = (int A::* A::*)(icapcap);
}
// ----------- static_cast -------------
struct B : public A {}; // Single public base.
struct C1 : public virtual B {}; // Single virtual base.
struct C2 : public virtual B {};
struct D : public C1, public C2 {}; // Diamond
struct E : private A {}; // Single private base.
struct F : public C1 {}; // Single path to B with virtual.
struct G1 : public B {};
struct G2 : public B {};
struct H : public G1, public G2 {}; // Ambiguous path to B.
enum Enum { En1, En2 };
enum Onom { On1, On2 };
struct Co1 { operator int(); };
struct Co2 { Co2(int); };
struct Co3 { };
struct Co4 { Co4(Co3); operator Co3(); };
// Explicit implicits
void t_529_2()
{
int i = 1;
(void)(float)(i);
double d = 1.0;
(void)(float)(d);
(void)(int)(d);
(void)(char)(i);
(void)(unsigned long)(i);
(void)(int)(En1);
(void)(double)(En1);
(void)(int&)(i);
(void)(const int&)(i);
int ar[1];
(void)(const int*)(ar);
(void)(void (*)())(t_529_2);
(void)(void*)(0);
(void)(void*)((int*)0);
(void)(volatile const void*)((const int*)0);
(void)(A*)((B*)0);
(void)(A&)(*((B*)0));
(void)(const B*)((C1*)0);
(void)(B&)(*((C1*)0));
(void)(A*)((D*)0);
(void)(const A&)(*((D*)0));
(void)(int B::*)((int A::*)0);
(void)(void (B::*)())((void (A::*)())0);
(void)(A*)((E*)0); // C-style cast ignores access control
(void)(void*)((const int*)0); // const_cast appended
(void)(int)(Co1());
(void)(Co2)(1);
(void)(Co3)((Co4)(Co3()));
// Bad code below
//(void)(A*)((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}}
}
// Anything to void
void t_529_4()
{
(void)(1);
(void)(t_529_4);
}
// Static downcasts
void t_529_5_8()
{
(void)(B*)((A*)0);
(void)(B&)(*((A*)0));
(void)(const G1*)((A*)0);
(void)(const G1&)(*((A*)0));
(void)(B*)((const A*)0); // const_cast appended
(void)(B&)(*((const A*)0)); // const_cast appended
(void)(E*)((A*)0); // access control ignored
(void)(E&)(*((A*)0)); // access control ignored
// Bad code below
(void)(C1*)((A*)0); // expected-error {{cannot cast 'struct A *' to 'struct C1 *' via virtual base 'struct B'}}
(void)(C1&)(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct C1 &' via virtual base 'struct B'}}
(void)(D*)((A*)0); // expected-error {{cannot cast 'struct A *' to 'struct D *' via virtual base 'struct B'}}
(void)(D&)(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
(void)(H*)((A*)0); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)(H&)(*((A*)0)); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
// TODO: Test DR427. This requires user-defined conversions, though.
}
// Enum conversions
void t_529_7()
{
(void)(Enum)(1);
(void)(Enum)(1.0);
(void)(Onom)(En1);
// Bad code below
(void)(Enum)((int*)0); // expected-error {{C-style cast from 'int *' to 'enum Enum' is not allowed}}
}
// Void pointer to object pointer
void t_529_10()
{
(void)(int*)((void*)0);
(void)(const A*)((void*)0);
(void)(int*)((const void*)0); // const_cast appended
}
// Member pointer upcast.
void t_529_9()
{
(void)(int A::*)((int B::*)0);
// Bad code below
(void)(int A::*)((int H::*)0); // expected-error {{ambiguous conversion from pointer to member of derived class 'struct H'}}
(void)(int A::*)((int F::*)0); // expected-error {{conversion from pointer to member of class 'struct F'}}
}
// -------- reinterpret_cast -----------
enum test { testval = 1 };
struct structure { int m; };
typedef void (*fnptr)();
// Test conversion between pointer and integral types, as in p3 and p4.
void integral_conversion()
{
void *vp = (void*)(testval);
long l = (long)(vp);
(void)(float*)(l);
fnptr fnp = (fnptr)(l);
(void)(char)(fnp); // expected-error {{cast from pointer to smaller type 'char' loses information}}
(void)(long)(fnp);
}
void pointer_conversion()
{
int *p1 = 0;
float *p2 = (float*)(p1);
structure *p3 = (structure*)(p2);
typedef int **ppint;
ppint *deep = (ppint*)(p3);
(void)(fnptr*)(deep);
}
void constness()
{
int ***const ipppc = 0;
int const *icp = (int const*)(ipppc);
(void)(int*)(icp); // const_cast appended
int const *const **icpcpp = (int const* const**)(ipppc); // const_cast appended
int *ip = (int*)(icpcpp);
(void)(int const*)(ip);
(void)(int const* const* const*)(ipppc);
}
void fnptrs()
{
typedef int (*fnptr2)(int);
fnptr fp = 0;
(void)(fnptr2)(fp);
void *vp = (void*)(fp);
(void)(fnptr)(vp);
}
void refs()
{
long l = 0;
char &c = (char&)(l);
// Bad: from rvalue
(void)(int&)(&c); // expected-error {{C-style cast from rvalue to reference type 'int &'}}
}
void memptrs()
{
const int structure::*psi = 0;
(void)(const float structure::*)(psi);
(void)(int structure::*)(psi); // const_cast appended
void (structure::*psf)() = 0;
(void)(int (structure::*)())(psf);
(void)(void (structure::*)())(psi); // expected-error {{C-style cast from 'int const struct structure::*' to 'void (struct structure::*)()' is not allowed}}
(void)(int structure::*)(psf); // expected-error {{C-style cast from 'void (struct structure::*)()' to 'int struct structure::*' is not allowed}}
}

Просмотреть файл

@ -50,7 +50,7 @@ void foo5()
void foo6()
{
(void)(int(1)); //expression
(void)(int())1; // expected-error{{used type}}
(void)(int())1; // expected-error{{to 'int ()'}}
}
// [dcl.ambig.res]p7:

Просмотреть файл

@ -19,7 +19,7 @@ void f() {
(int(1)); // expected-warning {{expression result unused}}
// type-id
(int())1; // expected-error {{used type 'int ()' where arithmetic or pointer type is required}}
(int())1; // expected-error {{C-style cast from 'int' to 'int ()' is not allowed}}
// Declarations.
int fd(T(a)); // expected-warning {{parentheses were disambiguated as a function declarator}}

Просмотреть файл

@ -1,11 +1,11 @@
// RUN: clang-cc -fsyntax-only -verify %s
// RUN: clang-cc -fsyntax-only -verify -faccess-control %s
struct A {};
struct B : public A {}; // Single public base.
struct C1 : public virtual B {}; // Single virtual base.
struct C2 : public virtual B {};
struct D : public C1, public C2 {}; // Diamond
struct E : private A {}; // Single private base.
struct E : private A {}; // Single private base. expected-note 2 {{'private' inheritance specifier here}}
struct F : public C1 {}; // Single path to B with virtual.
struct G1 : public B {};
struct G2 : public B {};
@ -14,6 +14,11 @@ struct H : public G1, public G2 {}; // Ambiguous path to B.
enum Enum { En1, En2 };
enum Onom { On1, On2 };
struct Co1 { operator int(); };
struct Co2 { Co2(int); };
struct Co3 { };
struct Co4 { Co4(Co3); operator Co3(); };
// Explicit implicits
void t_529_2()
{
@ -45,7 +50,9 @@ void t_529_2()
(void)static_cast<int B::*>((int A::*)0);
(void)static_cast<void (B::*)()>((void (A::*)())0);
// TODO: User-defined conversions
(void)static_cast<int>(Co1());
(void)static_cast<Co2>(1);
(void)static_cast<Co3>(static_cast<Co4>(Co3()));
// Bad code below
@ -80,11 +87,10 @@ void t_529_5_8()
(void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
(void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'struct A const *' to 'struct B *' casts away constness}}
(void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'struct A const' to 'struct B &' casts away constness}}
// Accessibility is not yet tested
//(void)static_cast<E*>((A*)0); // {{static_cast from 'struct A *' to 'struct E *' is not allowed}}
//(void)static_cast<E&>(*((A*)0)); // {{static_cast from 'struct A' to 'struct E &' is not allowed}}
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous static_cast from base 'struct A' to derived 'struct 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 static_cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<E*>((A*)0); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
(void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct 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 'struct A' to derived 'struct 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 'struct B *' to 'struct E *' is not allowed}}
(void)static_cast<E&>(*((B*)0)); // expected-error {{non-const lvalue reference to type 'struct E' cannot be initialized with a value of type 'struct B'}}

Просмотреть файл

@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
struct A { int x; };
struct A { int x; }; // expected-note 2 {{candidate}}
class Base {
public:
@ -23,7 +23,7 @@ struct Constructible {
template<typename T, typename U>
struct CStyleCast0 {
void f(T t) {
(void)((U)t); // FIXME:ugly expected-error{{operand}}
(void)((U)t); // expected-error{{C-style cast from 'struct A' to 'int'}}
}
};
@ -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}}
(void)static_cast<U>(t); // expected-error{{initialization of 'struct 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); // FIXME:ugly expected-error{{operand}}
(void)U(t); // expected-error{{C-style cast from 'struct A' to 'int'}}
}
};

Просмотреть файл

@ -540,10 +540,10 @@ welcome!</p>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.3 [expr.type.conv]</td>
<td class="complete" align="center"></td>
<td class="complete" align="center"></td>
<td class="basic"></td>
<td class="medium" align="center"></td>
<td class="advanced"></td>
<td></td>
<td>Only between non-class types</td>
<td>Allows some invalid pointer conversions, AST has little information</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.4 [expr.pseudo]</td>
@ -588,10 +588,10 @@ welcome!</p>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.9 [expr.static.cast]</td>
<td class="complete" align="center"></td>
<td class="complete" align="center"></td>
<td class="medium" align="center"></td>
<td class="advanced" align="center"></td>
<td></td>
<td>Some custom conversions don't work.</td>
<td>Allows some invalid pointer conversions, AST has little information</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.10 [expr.reinterpret.cast]</td>
@ -694,10 +694,10 @@ welcome!</p>
<tr>
<td>&nbsp;&nbsp;5.4 [expr.cast]</td>
<td class="complete" align="center"></td>
<td class="complete" align="center"></td>
<td class="medium"></td>
<td class="medium" align="center"></td>
<td class="advanced"></td>
<td></td>
<td>Too lenient, and may not always have correct semantics</td>
<td>Allows some invalid pointer conversions, AST has little information</td>
</tr>
<tr>
<td>&nbsp;&nbsp;5.5 [expr.mptr.oper]</td>