llvm-project/clang/lib/Sema/SemaCast.cpp

2455 lines
94 KiB
C++
Raw Normal View History

//===--- SemaCast.cpp - Semantic Analysis for Casts -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for cast expressions, including
// 1) C-style casts like '(int) x'
// 2) C++ functional casts like 'int(x)'
// 3) C++ named casts like 'static_cast<int>(x)'
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Initialization.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
using namespace clang;
enum TryCastResult {
TC_NotApplicable, ///< The cast method is not applicable.
TC_Success, ///< The cast method is appropriate and successful.
TC_Failed ///< The cast method is appropriate, but failed. A
///< diagnostic has been emitted.
};
enum CastType {
CT_Const, ///< const_cast
CT_Static, ///< static_cast
CT_Reinterpret, ///< reinterpret_cast
CT_Dynamic, ///< dynamic_cast
CT_CStyle, ///< (Type)expr
CT_Functional ///< Type(expr)
};
namespace {
struct CastOperation {
CastOperation(Sema &S, QualType destType, ExprResult src)
: Self(S), SrcExpr(src), DestType(destType),
ResultType(destType.getNonLValueExprType(S.Context)),
ValueKind(Expr::getValueKindForType(destType)),
Kind(CK_Dependent), IsARCUnbridgedCast(false) {
if (const BuiltinType *placeholder =
src.get()->getType()->getAsPlaceholderType()) {
PlaceholderKind = placeholder->getKind();
} else {
PlaceholderKind = (BuiltinType::Kind) 0;
}
}
Sema &Self;
ExprResult SrcExpr;
QualType DestType;
QualType ResultType;
ExprValueKind ValueKind;
CastKind Kind;
BuiltinType::Kind PlaceholderKind;
CXXCastPath BasePath;
bool IsARCUnbridgedCast;
SourceRange OpRange;
SourceRange DestRange;
// Top-level semantics-checking routines.
void CheckConstCast();
void CheckReinterpretCast();
void CheckStaticCast();
void CheckDynamicCast();
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
/// Complete an apparently-successful cast operation that yields
/// the given expression.
ExprResult complete(CastExpr *castExpr) {
// If this is an unbridged cast, wrap the result in an implicit
// cast that yields the unbridged-cast placeholder type.
if (IsARCUnbridgedCast) {
castExpr = ImplicitCastExpr::Create(Self.Context,
Self.Context.ARCUnbridgedCastTy,
CK_Dependent, castExpr, nullptr,
castExpr->getValueKind());
}
return castExpr;
}
// Internal convenience methods.
/// Try to handle the given placeholder expression kind. Return
/// true if the source expression has the appropriate placeholder
/// kind. A placeholder can only be claimed once.
bool claimPlaceholder(BuiltinType::Kind K) {
if (PlaceholderKind != K) return false;
PlaceholderKind = (BuiltinType::Kind) 0;
return true;
}
bool isPlaceholder() const {
return PlaceholderKind != 0;
}
bool isPlaceholder(BuiltinType::Kind K) const {
return PlaceholderKind == K;
}
void checkCastAlign() {
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}
void checkObjCARCConversion(Sema::CheckedConversionKind CCK) {
assert(Self.getLangOpts().ObjCAutoRefCount);
Expr *src = SrcExpr.get();
if (Self.CheckObjCARCConversion(OpRange, DestType, src, CCK) ==
Sema::ACR_unbridged)
IsARCUnbridgedCast = true;
SrcExpr = src;
}
/// Check for and handle non-overload placeholder expressions.
void checkNonOverloadPlaceholders() {
if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload))
return;
SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
PlaceholderKind = (BuiltinType::Kind) 0;
}
};
}
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic
// to emit if no other way succeeds. If their way of casting is appropriate but
// fails, they return TC_Failed and *must* set diag; they can set it to 0 if
// they emit a specialized diagnostic.
// All diagnostics returned by these functions must expect the same three
// arguments:
// %0: Cast Type (a value from the CastType enumeration)
// %1: Source Type
// %2: Destination Type
static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
QualType DestType, bool CStyle,
CastKind &Kind,
CXXCastPath &BasePath,
unsigned &msg);
static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath);
static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath);
static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
CanQualType DestType, bool CStyle,
const SourceRange &OpRange,
QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath);
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr,
QualType SrcType,
QualType DestType,bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath);
static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg, CastKind &Kind,
bool ListInitialization);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath,
bool ListInitialization);
static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
2009-09-26 08:12:34 +08:00
unsigned &msg,
CastKind &Kind);
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
SourceLocation LAngleBracketLoc, Declarator &D,
SourceLocation RAngleBracketLoc,
SourceLocation LParenLoc, Expr *E,
SourceLocation RParenLoc) {
assert(!D.isInvalidType());
TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, E->getType());
if (D.isInvalidType())
return ExprError();
if (getLangOpts().CPlusPlus) {
// Check that there are no default arguments (C++ only).
CheckExtraCXXDefaultArguments(D);
}
return BuildCXXNamedCast(OpLoc, Kind, TInfo, E,
SourceRange(LAngleBracketLoc, RAngleBracketLoc),
SourceRange(LParenLoc, RParenLoc));
}
ExprResult
Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
TypeSourceInfo *DestTInfo, Expr *E,
SourceRange AngleBrackets, SourceRange Parens) {
ExprResult Ex = E;
QualType DestType = DestTInfo->getType();
// If the type is dependent, we won't do the semantic analysis now.
// FIXME: should we check this in a more fine-grained manner?
bool TypeDependent = DestType->isDependentType() ||
Ex.get()->isTypeDependent() ||
Ex.get()->isValueDependent();
CastOperation Op(*this, DestType, E);
Op.OpRange = SourceRange(OpLoc, Parens.getEnd());
Op.DestRange = AngleBrackets;
switch (Kind) {
default: llvm_unreachable("Unknown C++ cast!");
case tok::kw_const_cast:
if (!TypeDependent) {
Op.CheckConstCast();
if (Op.SrcExpr.isInvalid())
return ExprError();
}
return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.SrcExpr.get(), DestTInfo,
OpLoc, Parens.getEnd(),
AngleBrackets));
case tok::kw_dynamic_cast: {
if (!TypeDependent) {
Op.CheckDynamicCast();
if (Op.SrcExpr.isInvalid())
return ExprError();
}
return Op.complete(CXXDynamicCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, DestTInfo,
OpLoc, Parens.getEnd(),
AngleBrackets));
}
case tok::kw_reinterpret_cast: {
if (!TypeDependent) {
Op.CheckReinterpretCast();
if (Op.SrcExpr.isInvalid())
return ExprError();
}
return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
nullptr, DestTInfo, OpLoc,
Parens.getEnd(),
AngleBrackets));
}
2009-08-08 06:21:05 +08:00
case tok::kw_static_cast: {
if (!TypeDependent) {
Op.CheckStaticCast();
if (Op.SrcExpr.isInvalid())
return ExprError();
}
return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, DestTInfo,
OpLoc, Parens.getEnd(),
AngleBrackets));
2009-08-08 06:21:05 +08:00
}
}
}
/// 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,
bool listInitialization) {
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
= (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
range, listInitialization)
: (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range,
listInitialization)
: InitializationKind::CreateCast(/*type range?*/ range);
InitializationSequence sequence(S, entity, initKind, src);
assert(sequence.Failed() && "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");
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);
return true;
}
/// Diagnose a failed cast.
static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
SourceRange opRange, Expr *src, QualType destType,
bool listInitialization) {
if (msg == diag::err_bad_cxx_cast_generic &&
tryDiagnoseOverloadedCast(S, castType, opRange, src, destType,
listInitialization))
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,
/// this one doesn't care if the two pointers-to-member don't point into the
/// same class. This is because CastsAwayConstness doesn't care.
static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
const PointerType *T1PtrType = T1->getAs<PointerType>(),
*T2PtrType = T2->getAs<PointerType>();
if (T1PtrType && T2PtrType) {
T1 = T1PtrType->getPointeeType();
T2 = T2PtrType->getPointeeType();
return true;
}
const ObjCObjectPointerType *T1ObjCPtrType =
T1->getAs<ObjCObjectPointerType>(),
*T2ObjCPtrType =
T2->getAs<ObjCObjectPointerType>();
if (T1ObjCPtrType) {
if (T2ObjCPtrType) {
T1 = T1ObjCPtrType->getPointeeType();
T2 = T2ObjCPtrType->getPointeeType();
return true;
}
else if (T2PtrType) {
T1 = T1ObjCPtrType->getPointeeType();
T2 = T2PtrType->getPointeeType();
return true;
}
}
else if (T2ObjCPtrType) {
if (T1PtrType) {
T2 = T2ObjCPtrType->getPointeeType();
T1 = T1PtrType->getPointeeType();
return true;
}
}
const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(),
*T2MPType = T2->getAs<MemberPointerType>();
if (T1MPType && T2MPType) {
T1 = T1MPType->getPointeeType();
T2 = T2MPType->getPointeeType();
return true;
}
const BlockPointerType *T1BPType = T1->getAs<BlockPointerType>(),
*T2BPType = T2->getAs<BlockPointerType>();
if (T1BPType && T2BPType) {
T1 = T1BPType->getPointeeType();
T2 = T2BPType->getPointeeType();
return true;
}
return false;
}
/// CastsAwayConstness - Check if the pointer conversion from SrcType to
/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
/// the cast checkers. Both arguments must denote pointer (possibly to member)
/// types.
///
/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers.
///
/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers.
static bool
CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
bool CheckCVR, bool CheckObjCLifetime,
QualType *TheOffendingSrcType = nullptr,
QualType *TheOffendingDestType = nullptr,
Qualifiers *CastAwayQualifiers = nullptr) {
// If the only checking we care about is for Objective-C lifetime qualifiers,
// and we're not in ARC mode, there's nothing to check.
if (!CheckCVR && CheckObjCLifetime &&
!Self.Context.getLangOpts().ObjCAutoRefCount)
return false;
// Casting away constness is defined in C++ 5.2.11p8 with reference to
// C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
// the rules are non-trivial. So first we construct Tcv *...cv* as described
// in C++ 5.2.11p8.
assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() ||
SrcType->isBlockPointerType()) &&
"Source type is not pointer or pointer to member.");
assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() ||
DestType->isBlockPointerType()) &&
"Destination type is not pointer or pointer to member.");
QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
UnwrappedDestType = Self.Context.getCanonicalType(DestType);
SmallVector<Qualifiers, 8> cv1, cv2;
// Find the qualifiers. We only care about cvr-qualifiers for the
// purpose of this check, because other qualifiers (address spaces,
// Objective-C GC, etc.) are part of the type's identity.
QualType PrevUnwrappedSrcType = UnwrappedSrcType;
QualType PrevUnwrappedDestType = UnwrappedDestType;
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
// Determine the relevant qualifiers at this level.
Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
Qualifiers RetainedSrcQuals, RetainedDestQuals;
if (CheckCVR) {
RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
if (RetainedSrcQuals != RetainedDestQuals && TheOffendingSrcType &&
TheOffendingDestType && CastAwayQualifiers) {
*TheOffendingSrcType = PrevUnwrappedSrcType;
*TheOffendingDestType = PrevUnwrappedDestType;
*CastAwayQualifiers = RetainedSrcQuals - RetainedDestQuals;
}
}
if (CheckObjCLifetime &&
!DestQuals.compatiblyIncludesObjCLifetime(SrcQuals))
return true;
cv1.push_back(RetainedSrcQuals);
cv2.push_back(RetainedDestQuals);
PrevUnwrappedSrcType = UnwrappedSrcType;
PrevUnwrappedDestType = UnwrappedDestType;
}
if (cv1.empty())
return false;
// Construct void pointers with those qualifiers (in reverse order of
// unwrapping, of course).
QualType SrcConstruct = Self.Context.VoidTy;
QualType DestConstruct = Self.Context.VoidTy;
ASTContext &Context = Self.Context;
for (SmallVectorImpl<Qualifiers>::reverse_iterator i1 = cv1.rbegin(),
i2 = cv2.rbegin();
i1 != cv1.rend(); ++i1, ++i2) {
SrcConstruct
= Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1));
DestConstruct
= Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2));
}
// Test if they're compatible.
bool ObjCLifetimeConversion;
return SrcConstruct != DestConstruct &&
!Self.IsQualificationConversion(SrcConstruct, DestConstruct, false,
ObjCLifetimeConversion);
}
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
void CastOperation::CheckDynamicCast() {
if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.get());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
QualType OrigSrcType = SrcExpr.get()->getType();
QualType DestType = Self.Context.getCanonicalType(this->DestType);
// C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
// or "pointer to cv void".
QualType DestPointee;
const PointerType *DestPointer = DestType->getAs<PointerType>();
const ReferenceType *DestReference = nullptr;
if (DestPointer) {
DestPointee = DestPointer->getPointeeType();
} else if ((DestReference = DestType->getAs<ReferenceType>())) {
DestPointee = DestReference->getPointeeType();
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
<< this->DestType << DestRange;
SrcExpr = ExprError();
return;
}
const RecordType *DestRecord = DestPointee->getAs<RecordType>();
if (DestPointee->isVoidType()) {
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
diag::err_bad_dynamic_cast_incomplete,
DestRange)) {
SrcExpr = ExprError();
return;
}
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
<< DestPointee.getUnqualifiedType() << DestRange;
SrcExpr = ExprError();
return;
}
// C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
// complete class type, [...]. If T is an lvalue reference type, v shall be
// an lvalue of a complete class type, [...]. If T is an rvalue reference
// type, v shall be an expression having a complete class type, [...]
QualType SrcType = Self.Context.getCanonicalType(OrigSrcType);
QualType SrcPointee;
if (DestPointer) {
if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) {
SrcPointee = SrcPointer->getPointeeType();
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
<< OrigSrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
} else if (DestReference->isLValueReferenceType()) {
if (!SrcExpr.get()->isLValue()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
<< CT_Dynamic << OrigSrcType << this->DestType << OpRange;
}
SrcPointee = SrcType;
} else {
// If we're dynamic_casting from a prvalue to an rvalue reference, we need
// to materialize the prvalue before we bind the reference to it.
if (SrcExpr.get()->isRValue())
SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
SrcType, SrcExpr.get(), /*IsLValueReference*/false);
SrcPointee = SrcType;
}
const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
diag::err_bad_dynamic_cast_incomplete,
SrcExpr.get())) {
SrcExpr = ExprError();
return;
}
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class)
<< SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
assert((DestPointer || DestReference) &&
"Bad destination non-ptr/ref slipped through.");
assert((DestRecord || DestPointee->isVoidType()) &&
"Bad destination pointee slipped through.");
assert(SrcRecord && "Bad source pointee slipped through.");
// C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
<< CT_Dynamic << OrigSrcType << this->DestType << OpRange;
SrcExpr = ExprError();
return;
}
// C++ 5.2.7p3: If the type of v is the same as the required result type,
// [except for cv].
if (DestRecord == SrcRecord) {
Kind = CK_NoOp;
return;
}
// C++ 5.2.7p5
// Upcasts are resolved statically.
if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
OpRange.getBegin(), OpRange,
&BasePath)) {
SrcExpr = ExprError();
return;
}
Kind = CK_DerivedToBase;
Rework when and how vtables are emitted, by tracking where vtables are "used" (e.g., we will refer to the vtable in the generated code) and when they are defined (i.e., because we've seen the key function definition). Previously, we were effectively tracking "potential definitions" rather than uses, so we were a bit too eager about emitting vtables for classes without key functions. The new scheme: - For every use of a vtable, Sema calls MarkVTableUsed() to indicate the use. For example, this occurs when calling a virtual member function of the class, defining a constructor of that class type, dynamic_cast'ing from that type to a derived class, casting to/through a virtual base class, etc. - For every definition of a vtable, Sema calls MarkVTableUsed() to indicate the definition. This happens at the end of the translation unit for classes whose key function has been defined (so we can delay computation of the key function; see PR6564), and will also occur with explicit template instantiation definitions. - For every vtable defined/used, we mark all of the virtual member functions of that vtable as defined/used, unless we know that the key function is in another translation unit. This instantiates virtual member functions when needed. - At the end of the translation unit, Sema tells CodeGen (via the ASTConsumer) which vtables must be defined (CodeGen will define them) and which may be used (for which CodeGen will define the vtables lazily). From a language perspective, both the old and the new schemes are permissible: we're allowed to instantiate virtual member functions whenever we want per the standard. However, all other C++ compilers were more lazy than we were, and our eagerness was both a performance issue (we instantiated too much) and a portability problem (we broke Boost test cases, which now pass). Notes: (1) There's a ton of churn in the tests, because the order in which vtables get emitted to IR has changed. I've tried to isolate some of the larger tests from these issues. (2) Some diagnostics related to implicitly-instantiated/implicitly-defined virtual member functions have moved to the point of first use/definition. It's better this way. (3) I could use a review of the places where we MarkVTableUsed, to see if I missed any place where the language effectively requires a vtable. Fixes PR7114 and PR6564. llvm-svn: 103718
2010-05-14 00:44:06 +08:00
// If we are casting to or through a virtual base class, we need a
// vtable.
if (Self.BasePathInvolvesVirtualBase(BasePath))
Self.MarkVTableUsed(OpRange.getBegin(),
cast<CXXRecordDecl>(SrcRecord->getDecl()));
return;
}
// C++ 5.2.7p6: Otherwise, v shall be [polymorphic].
const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition();
assert(SrcDecl && "Definition missing");
if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
<< SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
}
Rework when and how vtables are emitted, by tracking where vtables are "used" (e.g., we will refer to the vtable in the generated code) and when they are defined (i.e., because we've seen the key function definition). Previously, we were effectively tracking "potential definitions" rather than uses, so we were a bit too eager about emitting vtables for classes without key functions. The new scheme: - For every use of a vtable, Sema calls MarkVTableUsed() to indicate the use. For example, this occurs when calling a virtual member function of the class, defining a constructor of that class type, dynamic_cast'ing from that type to a derived class, casting to/through a virtual base class, etc. - For every definition of a vtable, Sema calls MarkVTableUsed() to indicate the definition. This happens at the end of the translation unit for classes whose key function has been defined (so we can delay computation of the key function; see PR6564), and will also occur with explicit template instantiation definitions. - For every vtable defined/used, we mark all of the virtual member functions of that vtable as defined/used, unless we know that the key function is in another translation unit. This instantiates virtual member functions when needed. - At the end of the translation unit, Sema tells CodeGen (via the ASTConsumer) which vtables must be defined (CodeGen will define them) and which may be used (for which CodeGen will define the vtables lazily). From a language perspective, both the old and the new schemes are permissible: we're allowed to instantiate virtual member functions whenever we want per the standard. However, all other C++ compilers were more lazy than we were, and our eagerness was both a performance issue (we instantiated too much) and a portability problem (we broke Boost test cases, which now pass). Notes: (1) There's a ton of churn in the tests, because the order in which vtables get emitted to IR has changed. I've tried to isolate some of the larger tests from these issues. (2) Some diagnostics related to implicitly-instantiated/implicitly-defined virtual member functions have moved to the point of first use/definition. It's better this way. (3) I could use a review of the places where we MarkVTableUsed, to see if I missed any place where the language effectively requires a vtable. Fixes PR7114 and PR6564. llvm-svn: 103718
2010-05-14 00:44:06 +08:00
Self.MarkVTableUsed(OpRange.getBegin(),
cast<CXXRecordDecl>(SrcRecord->getDecl()));
// dynamic_cast is not available with -fno-rtti.
// As an exception, dynamic_cast to void* is available because it doesn't
// use RTTI.
if (!Self.getLangOpts().RTTI && !DestPointee->isVoidType()) {
Self.Diag(OpRange.getBegin(), diag::err_no_dynamic_cast_with_fno_rtti);
SrcExpr = ExprError();
return;
}
// Done. Everything else is run-time checks.
Kind = CK_Dynamic;
}
/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid.
/// Refer to C++ 5.2.11 for details. const_cast is typically used in code
/// like this:
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
void CastOperation::CheckConstCast() {
if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.get());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
&& msg != 0) {
Self.Diag(OpRange.getBegin(), msg) << CT_Const
<< SrcExpr.get()->getType() << DestType << OpRange;
SrcExpr = ExprError();
}
}
/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
/// or downcast between respective pointers or references.
static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
QualType DestType,
SourceRange OpRange) {
QualType SrcType = SrcExpr->getType();
// When casting from pointer or reference, get pointee type; use original
// type otherwise.
const CXXRecordDecl *SrcPointeeRD = SrcType->getPointeeCXXRecordDecl();
const CXXRecordDecl *SrcRD =
SrcPointeeRD ? SrcPointeeRD : SrcType->getAsCXXRecordDecl();
// Examining subobjects for records is only possible if the complete and
// valid definition is available. Also, template instantiation is not
// allowed here.
if (!SrcRD || !SrcRD->isCompleteDefinition() || SrcRD->isInvalidDecl())
return;
const CXXRecordDecl *DestRD = DestType->getPointeeCXXRecordDecl();
if (!DestRD || !DestRD->isCompleteDefinition() || DestRD->isInvalidDecl())
return;
enum {
ReinterpretUpcast,
ReinterpretDowncast
} ReinterpretKind;
CXXBasePaths BasePaths;
if (SrcRD->isDerivedFrom(DestRD, BasePaths))
ReinterpretKind = ReinterpretUpcast;
else if (DestRD->isDerivedFrom(SrcRD, BasePaths))
ReinterpretKind = ReinterpretDowncast;
else
return;
bool VirtualBase = true;
bool NonZeroOffset = false;
for (CXXBasePaths::const_paths_iterator I = BasePaths.begin(),
E = BasePaths.end();
I != E; ++I) {
const CXXBasePath &Path = *I;
CharUnits Offset = CharUnits::Zero();
bool IsVirtual = false;
for (CXXBasePath::const_iterator IElem = Path.begin(), EElem = Path.end();
IElem != EElem; ++IElem) {
IsVirtual = IElem->Base->isVirtual();
if (IsVirtual)
break;
const CXXRecordDecl *BaseRD = IElem->Base->getType()->getAsCXXRecordDecl();
assert(BaseRD && "Base type should be a valid unqualified class type");
// Don't check if any base has invalid declaration or has no definition
// since it has no layout info.
const CXXRecordDecl *Class = IElem->Class,
*ClassDefinition = Class->getDefinition();
if (Class->isInvalidDecl() || !ClassDefinition ||
!ClassDefinition->isCompleteDefinition())
return;
const ASTRecordLayout &DerivedLayout =
Self.Context.getASTRecordLayout(Class);
Offset += DerivedLayout.getBaseClassOffset(BaseRD);
}
if (!IsVirtual) {
// Don't warn if any path is a non-virtually derived base at offset zero.
if (Offset.isZero())
return;
// Offset makes sense only for non-virtual bases.
else
NonZeroOffset = true;
}
VirtualBase = VirtualBase && IsVirtual;
}
(void) NonZeroOffset; // Silence set but not used warning.
assert((VirtualBase || NonZeroOffset) &&
"Should have returned if has non-virtual base with zero offset");
QualType BaseType =
ReinterpretKind == ReinterpretUpcast? DestType : SrcType;
QualType DerivedType =
ReinterpretKind == ReinterpretUpcast? SrcType : DestType;
SourceLocation BeginLoc = OpRange.getBegin();
Self.Diag(BeginLoc, diag::warn_reinterpret_different_from_static)
<< DerivedType << BaseType << !VirtualBase << int(ReinterpretKind)
<< OpRange;
Self.Diag(BeginLoc, diag::note_reinterpret_updowncast_use_static)
<< int(ReinterpretKind)
<< FixItHint::CreateReplacement(BeginLoc, "static_cast");
}
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
/// valid.
/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
/// like this:
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
void CastOperation::CheckReinterpretCast() {
if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload))
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr =
TryReinterpretCast(Self, SrcExpr, DestType,
/*CStyle*/false, OpRange, msg, Kind);
if (tcr != TC_Success && msg != 0)
{
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
//FIXME: &f<int>; is overloaded and resolvable
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload)
<< OverloadExpr::find(SrcExpr.get()).Expression->getName()
<< DestType << OpRange;
Self.NoteAllOverloadCandidates(SrcExpr.get());
} else {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(),
DestType, /*listInitialization=*/false);
}
SrcExpr = ExprError();
} else if (tcr == TC_Success) {
if (Self.getLangOpts().ObjCAutoRefCount)
checkObjCARCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
}
}
/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid.
/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making
/// implicit conversions explicit and getting rid of data loss warnings.
void CastOperation::CheckStaticCast() {
if (isPlaceholder()) {
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid())
return;
}
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
if (DestType->isVoidType()) {
Kind = CK_ToVoid;
if (claimPlaceholder(BuiltinType::Overload)) {
Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr,
false, // Decay Function to ptr
true, // Complain
OpRange, DestType, diag::err_bad_static_cast_overload);
if (SrcExpr.isInvalid())
return;
}
SrcExpr = Self.IgnoredValueConversions(SrcExpr.get());
return;
}
if (ValueKind == VK_RValue && !DestType->isRecordType() &&
!isPlaceholder(BuiltinType::Overload)) {
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
}
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr
= TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
Kind, BasePath, /*ListInitialization=*/false);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
OverloadExpr* oe = OverloadExpr::find(SrcExpr.get()).Expression;
Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload)
<< oe->getName() << DestType << OpRange
<< oe->getQualifierLoc().getSourceRange();
Self.NoteAllOverloadCandidates(SrcExpr.get());
} else {
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType,
/*listInitialization=*/false);
}
SrcExpr = ExprError();
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
checkCastAlign();
if (Self.getLangOpts().ObjCAutoRefCount)
checkObjCARCConversion(Sema::CCK_OtherCast);
} else if (Kind == CK_BitCast) {
checkCastAlign();
}
}
/// TryStaticCast - Check if a static cast can be performed, and do so if
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath,
bool ListInitialization) {
// Determine whether we have the semantics of a C-style cast.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
// struct B : public A {
// B(); B(const A&);
// };
// const A &a = B();
// the cast static_cast<const B&>(a) could be seen as either a static
// reference downcast, or an explicit invocation of the user-defined
// conversion using B's conversion constructor.
// DR 427 specifies that the downcast is to be applied here.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
// Done outside this function.
TryCastResult tcr;
// C++ 5.2.9p5, reference downcast.
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle,
OpRange, msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
// C++0x [expr.static.cast]p3:
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2
// T2" if "cv2 T2" is reference-compatible with "cv1 T1".
tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind,
BasePath, msg);
if (tcr != TC_NotApplicable)
return tcr;
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
Kind, ListInitialization);
if (SrcExpr.isInvalid())
return TC_Failed;
2009-09-26 08:12:34 +08:00
if (tcr != TC_NotApplicable)
return tcr;
// C++ 5.2.9p6: May apply the reverse of any standard conversion, except
// lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean
// conversions, subject to further restrictions.
// Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal
// of qualification conversions impossible.
// In the CStyle case, the earlier attempt to const_cast should have taken
// care of reverse qualification conversions.
QualType SrcType = Self.Context.getCanonicalType(SrcExpr.get()->getType());
// C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly
// converted to an integral type. [...] A value of a scoped enumeration type
// can also be explicitly converted to a floating-point type [...].
if (const EnumType *Enum = SrcType->getAs<EnumType>()) {
if (Enum->getDecl()->isScoped()) {
if (DestType->isBooleanType()) {
Kind = CK_IntegralToBoolean;
return TC_Success;
} else if (DestType->isIntegralType(Self.Context)) {
Kind = CK_IntegralCast;
return TC_Success;
} else if (DestType->isRealFloatingType()) {
Kind = CK_IntegralToFloating;
return TC_Success;
}
}
}
// Reverse integral promotion/conversion. All such conversions are themselves
// again integral promotions or conversions and are thus already handled by
// p2 (TryDirectInitialization above).
// (Note: any data loss warnings should be suppressed.)
// The exception is the reverse of enum->integer, i.e. integer->enum (and
// enum->enum). See also C++ 5.2.9p7.
// The same goes for reverse floating point promotion/conversion and
// floating-integral conversions. Again, only floating->enum is relevant.
if (DestType->isEnumeralType()) {
if (SrcType->isIntegralOrEnumerationType()) {
Kind = CK_IntegralCast;
return TC_Success;
} else if (SrcType->isRealFloatingType()) {
Kind = CK_FloatingToIntegral;
return TC_Success;
}
}
// Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
// C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
// Reverse member pointer conversion. C++ 4.11 specifies member pointer
// conversion. C++ 5.2.9p9 has additional information.
// DR54's access restrictions apply here also.
tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle,
OpRange, msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
// Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to
// void*. C++ 5.2.9p10 specifies additional restrictions, which really is
// just the usual constness stuff.
if (const PointerType *SrcPointer = SrcType->getAs<PointerType>()) {
QualType SrcPointee = SrcPointer->getPointeeType();
if (SrcPointee->isVoidType()) {
if (const PointerType *DestPointer = DestType->getAs<PointerType>()) {
QualType DestPointee = DestPointer->getPointeeType();
if (DestPointee->isIncompleteOrObjectType()) {
// This is definitely the intended conversion, but it might fail due
// to a qualifier violation. Note that we permit Objective-C lifetime
// and GC qualifier mismatches here.
if (!CStyle) {
Qualifiers DestPointeeQuals = DestPointee.getQualifiers();
Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers();
DestPointeeQuals.removeObjCGCAttr();
DestPointeeQuals.removeObjCLifetime();
SrcPointeeQuals.removeObjCGCAttr();
SrcPointeeQuals.removeObjCLifetime();
if (DestPointeeQuals != SrcPointeeQuals &&
!DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
}
Kind = CK_BitCast;
return TC_Success;
}
}
else if (DestType->isObjCObjectPointerType()) {
// allow both c-style cast and static_cast of objective-c pointers as
// they are pervasive.
Kind = CK_CPointerToObjCPointerCast;
return TC_Success;
}
else if (CStyle && DestType->isBlockPointerType()) {
// allow c-style cast of void * to block pointers.
Kind = CK_AnyPointerToBlockPointerCast;
return TC_Success;
}
}
}
// Allow arbitray objective-c pointer conversion with static casts.
if (SrcType->isObjCObjectPointerType() &&
DestType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
return TC_Success;
}
// Allow ns-pointer to cf-pointer conversion in either direction
// with static casts.
if (!CStyle &&
Self.CheckTollFreeBridgeStaticCast(DestType, SrcExpr.get(), Kind))
return TC_Success;
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
}
/// Tests whether a conversion according to N2844 is valid.
TryCastResult
TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, CastKind &Kind, CXXCastPath &BasePath,
unsigned &msg) {
// C++0x [expr.static.cast]p3:
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to
// cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
const RValueReferenceType *R = DestType->getAs<RValueReferenceType>();
if (!R)
return TC_NotApplicable;
if (!SrcExpr->isGLValue())
return TC_NotApplicable;
// Because we try the reference downcast before this function, from now on
// this is the only cast possibility, so we issue an error if we fail now.
// FIXME: Should allow casting away constness if CStyle.
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
FromType = FromType.getUnqualifiedType();
ToType = ToType.getUnqualifiedType();
}
if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
ToType, FromType,
DerivedToBase, ObjCConversion,
ObjCLifetimeConversion)
< Sema::Ref_Compatible_With_Added_Qualification) {
msg = diag::err_bad_lvalue_to_rvalue_cast;
return TC_Failed;
}
if (DerivedToBase) {
Kind = CK_DerivedToBase;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (!Self.IsDerivedFrom(SrcExpr->getType(), R->getPointeeType(), Paths))
return TC_NotApplicable;
Self.BuildBasePathArray(Paths, BasePath);
} else
Kind = CK_NoOp;
return TC_Success;
}
/// Tests whether a conversion according to C++ 5.2.9p5 is valid.
TryCastResult
TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath) {
// C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
// cast to type "reference to cv2 D", where D is a class derived from B,
// if a valid standard conversion from "pointer to D" to "pointer to B"
// exists, cv2 >= cv1, and B is not a virtual base class of D.
// In addition, DR54 clarifies that the base must be accessible in the
// current context. Although the wording of DR54 only applies to the pointer
// variant of this rule, the intent is clearly for it to apply to the this
// conversion as well.
const ReferenceType *DestReference = DestType->getAs<ReferenceType>();
if (!DestReference) {
return TC_NotApplicable;
}
bool RValueRef = DestReference->isRValueReferenceType();
if (!RValueRef && !SrcExpr->isLValue()) {
// We know the left side is an lvalue reference, so we can suggest a reason.
msg = diag::err_bad_cxx_cast_rvalue;
return TC_NotApplicable;
}
QualType DestPointee = DestReference->getPointeeType();
// FIXME: If the source is a prvalue, we should issue a warning (because the
// cast always has undefined behavior), and for AST consistency, we should
// materialize a temporary.
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcExpr->getType()),
Self.Context.getCanonicalType(DestPointee), CStyle,
OpRange, SrcExpr->getType(), DestType, msg, Kind,
BasePath);
}
/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
TryCastResult
TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
bool CStyle, const SourceRange &OpRange,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath) {
// C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
// type, can be converted to an rvalue of type "pointer to cv2 D", where D
// is a class derived from B, if a valid standard conversion from "pointer
// to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base
// class of D.
// In addition, DR54 clarifies that the base must be accessible in the
// current context.
const PointerType *DestPointer = DestType->getAs<PointerType>();
if (!DestPointer) {
return TC_NotApplicable;
}
const PointerType *SrcPointer = SrcType->getAs<PointerType>();
if (!SrcPointer) {
msg = diag::err_bad_static_cast_pointer_nonpointer;
return TC_NotApplicable;
}
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcPointer->getPointeeType()),
Self.Context.getCanonicalType(DestPointer->getPointeeType()),
CStyle, OpRange, SrcType, DestType, msg, Kind,
BasePath);
}
/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to
/// DestType is possible and allowed.
TryCastResult
TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath) {
// We can only work with complete types. But don't complain if it doesn't work
if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0) ||
Self.RequireCompleteType(OpRange.getBegin(), DestType, 0))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
if (!DestType->getAs<RecordType>() || !SrcType->getAs<RecordType>()) {
return TC_NotApplicable;
}
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
return TC_NotApplicable;
}
// Target type does derive from source type. Now we're serious. If an error
// appears now, it's not ignored.
// This may not be entirely in line with the standard. Take for example:
// struct A {};
// struct B : virtual A {
// B(A&);
// };
//
// void f()
// {
// (void)static_cast<const B&>(*((A*)0));
// }
// As far as the standard is concerned, p5 does not apply (A is virtual), so
// p2 should be used instead - "const B& t(*((A*)0));" is perfectly valid.
// However, both GCC and Comeau reject this example, and accepting it would
// mean more complex code if we're to preserve the nice error message.
// FIXME: Being 100% compliant here would be nice to have.
// Must preserve cv, as always, unless we're in C-style mode.
if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
if (Paths.isAmbiguous(SrcType.getUnqualifiedType())) {
// This code is analoguous to that in CheckDerivedToBaseConversion, except
// that it builds the paths in reverse order.
// To sum up: record all paths to the base and build a nice string from
// them. Use it to spice up the error message.
if (!Paths.isRecordingPaths()) {
Paths.clear();
Paths.setRecordingPaths(true);
Self.IsDerivedFrom(DestType, SrcType, Paths);
}
std::string PathDisplayStr;
std::set<unsigned> DisplayedPaths;
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
PI != PE; ++PI) {
if (DisplayedPaths.insert(PI->back().SubobjectNumber).second) {
// We haven't displayed a path to this particular base
// class subobject yet.
PathDisplayStr += "\n ";
for (CXXBasePath::const_reverse_iterator EI = PI->rbegin(),
EE = PI->rend();
EI != EE; ++EI)
PathDisplayStr += EI->Base->getType().getAsString() + " -> ";
PathDisplayStr += QualType(DestType).getAsString();
}
}
Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
<< QualType(SrcType).getUnqualifiedType()
<< QualType(DestType).getUnqualifiedType()
<< PathDisplayStr << OpRange;
msg = 0;
return TC_Failed;
}
if (Paths.getDetectedVirtual() != nullptr) {
QualType VirtualBase(Paths.getDetectedVirtual(), 0);
Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual)
<< OrigSrcType << OrigDestType << VirtualBase << OpRange;
msg = 0;
return TC_Failed;
}
if (!CStyle) {
switch (Self.CheckBaseClassAccess(OpRange.getBegin(),
SrcType, DestType,
Paths.front(),
diag::err_downcast_from_inaccessible_base)) {
case Sema::AR_accessible:
case Sema::AR_delayed: // be optimistic
case Sema::AR_dependent: // be optimistic
break;
case Sema::AR_inaccessible:
msg = 0;
return TC_Failed;
}
}
Self.BuildBasePathArray(Paths, BasePath);
Kind = CK_BaseToDerived;
return TC_Success;
}
/// TryStaticMemberPointerUpcast - Tests whether a conversion according to
/// C++ 5.2.9p9 is valid:
///
/// An rvalue of type "pointer to member of D of type cv1 T" can be
/// converted to an rvalue of type "pointer to member of B of type cv2 T",
/// where B is a base class of D [...].
///
TryCastResult
TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath) {
const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>();
if (!DestMemPtr)
return TC_NotApplicable;
bool WasOverloadedFunction = false;
DeclAccessPair FoundOverload;
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
if (FunctionDecl *Fn
= Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), DestType, false,
FoundOverload)) {
CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
SrcType = Self.Context.getMemberPointerType(Fn->getType(),
Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
WasOverloadedFunction = true;
}
}
const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
if (!SrcMemPtr) {
msg = diag::err_bad_static_cast_member_pointer_nonmp;
return TC_NotApplicable;
}
// T == T, modulo cv
if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(),
DestMemPtr->getPointeeType()))
return TC_NotApplicable;
// B base of D
QualType SrcClass(SrcMemPtr->getClass(), 0);
QualType DestClass(DestMemPtr->getClass(), 0);
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (Self.RequireCompleteType(OpRange.getBegin(), SrcClass, 0) ||
!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
return TC_NotApplicable;
}
// B is a base of D. But is it an allowed base? If not, it's a hard error.
if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) {
Paths.clear();
Paths.setRecordingPaths(true);
bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths);
assert(StillOkay);
(void)StillOkay;
std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths);
Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv)
<< 1 << SrcClass << DestClass << PathDisplayStr << OpRange;
msg = 0;
return TC_Failed;
}
if (const RecordType *VBase = Paths.getDetectedVirtual()) {
Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual)
<< SrcClass << DestClass << QualType(VBase, 0) << OpRange;
msg = 0;
return TC_Failed;
}
if (!CStyle) {
switch (Self.CheckBaseClassAccess(OpRange.getBegin(),
DestClass, SrcClass,
Paths.front(),
diag::err_upcast_to_inaccessible_base)) {
case Sema::AR_accessible:
case Sema::AR_delayed:
case Sema::AR_dependent:
// Optimistically assume that the delayed and dependent cases
// will work out.
break;
case Sema::AR_inaccessible:
msg = 0;
return TC_Failed;
}
}
if (WasOverloadedFunction) {
// Resolve the address of the overloaded function again, this time
// allowing complaints if something goes wrong.
FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
DestType,
true,
FoundOverload);
if (!Fn) {
msg = 0;
return TC_Failed;
}
SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn);
if (!SrcExpr.isUsable()) {
msg = 0;
return TC_Failed;
}
}
Self.BuildBasePathArray(Paths, BasePath);
Kind = CK_DerivedToBaseMemberPointer;
return TC_Success;
}
/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2
/// is valid:
///
/// An expression e can be explicitly converted to a type T using a
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_dynamic_cast_incomplete) ||
Self.RequireNonAbstractType(OpRange.getBegin(), DestType,
diag::err_allocation_of_abstract_type)) {
msg = 0;
return TC_Failed;
}
} else if (DestType->isMemberPointerType()) {
if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
Self.RequireCompleteType(OpRange.getBegin(), DestType, 0);
}
}
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= (CCK == Sema::CCK_CStyleCast)
? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange,
ListInitialization)
: (CCK == Sema::CCK_FunctionalCast)
? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
: InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
InitializationSequence InitSeq(Self, Entity, InitKind, SrcExprRaw);
// At this point of CheckStaticCast, if the destination is a reference,
// or the expression is an overload expression this has to work.
// There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
2009-09-26 08:12:34 +08:00
return TC_NotApplicable;
ExprResult Result = InitSeq.Perform(Self, Entity, InitKind, SrcExprRaw);
if (Result.isInvalid()) {
msg = 0;
return TC_Failed;
}
if (InitSeq.isConstructorInitialization())
Kind = CK_ConstructorConversion;
else
Kind = CK_NoOp;
SrcExpr = Result;
return TC_Success;
}
/// TryConstCast - See if a const_cast from source to destination is allowed,
/// and perform it if it is.
static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
unsigned &msg) {
DestType = Self.Context.getCanonicalType(DestType);
QualType SrcType = SrcExpr.get()->getType();
bool NeedToMaterializeTemporary = false;
if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) {
// C++11 5.2.11p4:
// if a pointer to T1 can be explicitly converted to the type "pointer to
// T2" using a const_cast, then the following conversions can also be
// made:
// -- an lvalue of type T1 can be explicitly converted to an lvalue of
// type T2 using the cast const_cast<T2&>;
// -- a glvalue of type T1 can be explicitly converted to an xvalue of
// type T2 using the cast const_cast<T2&&>; and
// -- if T1 is a class type, a prvalue of type T1 can be explicitly
// converted to an xvalue of type T2 using the cast const_cast<T2&&>.
if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr.get()->isLValue()) {
// Cannot const_cast non-lvalue to lvalue reference type. But if this
// is C-style, static_cast might find a way, so we simply suggest a
// message and tell the parent to keep searching.
msg = diag::err_bad_cxx_cast_rvalue;
return TC_NotApplicable;
}
if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) {
if (!SrcType->isRecordType()) {
// Cannot const_cast non-class prvalue to rvalue reference type. But if
// this is C-style, static_cast can do this.
msg = diag::err_bad_cxx_cast_rvalue;
return TC_NotApplicable;
}
// Materialize the class prvalue so that the const_cast can bind a
// reference to it.
NeedToMaterializeTemporary = true;
}
// It's not completely clear under the standard whether we can
// const_cast bit-field gl-values. Doing so would not be
// intrinsically complicated, but for now, we say no for
// consistency with other compilers and await the word of the
// committee.
if (SrcExpr.get()->refersToBitField()) {
msg = diag::err_bad_cxx_cast_bitfield;
return TC_NotApplicable;
}
DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
SrcType = Self.Context.getPointerType(SrcType);
}
// C++ 5.2.11p5: For a const_cast involving pointers to data members [...]
// the rules for const_cast are the same as those used for pointers.
if (!DestType->isPointerType() &&
!DestType->isMemberPointerType() &&
!DestType->isObjCObjectPointerType()) {
// Cannot cast to non-pointer, non-reference type. Note that, if DestType
// was a reference type, we converted it to a pointer above.
// The status of rvalue references isn't entirely clear, but it looks like
// conversion to them is simply invalid.
// C++ 5.2.11p3: For two pointer types [...]
if (!CStyle)
msg = diag::err_bad_const_cast_dest;
return TC_NotApplicable;
}
if (DestType->isFunctionPointerType() ||
DestType->isMemberFunctionPointerType()) {
// Cannot cast direct function pointers.
// C++ 5.2.11p2: [...] where T is any object type or the void type [...]
// T is the ultimate pointee of source and target type.
if (!CStyle)
msg = diag::err_bad_const_cast_dest;
return TC_NotApplicable;
}
SrcType = Self.Context.getCanonicalType(SrcType);
// Unwrap the pointers. Ignore qualifiers. Terminate early if the types are
// completely equal.
// C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers
// in multi-level pointers may change, but the level count must be the same,
// as must be the final pointee type.
while (SrcType != DestType &&
Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) {
Qualifiers SrcQuals, DestQuals;
SrcType = Self.Context.getUnqualifiedArrayType(SrcType, SrcQuals);
DestType = Self.Context.getUnqualifiedArrayType(DestType, DestQuals);
// const_cast is permitted to strip cvr-qualifiers, only. Make sure that
// the other qualifiers (e.g., address spaces) are identical.
SrcQuals.removeCVRQualifiers();
DestQuals.removeCVRQualifiers();
if (SrcQuals != DestQuals)
return TC_NotApplicable;
}
// Since we're dealing in canonical types, the remainder must be the same.
if (SrcType != DestType)
return TC_NotApplicable;
if (NeedToMaterializeTemporary)
// This is a const_cast from a class prvalue to an rvalue reference type.
// Materialize a temporary to store the result of the conversion.
SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
SrcType, SrcExpr.get(), /*IsLValueReference*/ false);
return TC_Success;
}
// Checks for undefined behavior in reinterpret_cast.
// The cases that is checked for is:
// *reinterpret_cast<T*>(&a)
// reinterpret_cast<T&>(a)
// where accessing 'a' as type 'T' will result in undefined behavior.
void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
bool IsDereference,
SourceRange Range) {
unsigned DiagID = IsDereference ?
diag::warn_pointer_indirection_from_incompatible_type :
diag::warn_undefined_reinterpret_cast;
if (Diags.isIgnored(DiagID, Range.getBegin()))
return;
QualType SrcTy, DestTy;
if (IsDereference) {
if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) {
return;
}
SrcTy = SrcType->getPointeeType();
DestTy = DestType->getPointeeType();
} else {
if (!DestType->getAs<ReferenceType>()) {
return;
}
SrcTy = SrcType;
DestTy = DestType->getPointeeType();
}
// Cast is compatible if the types are the same.
if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) {
return;
}
// or one of the types is a char or void type
if (DestTy->isAnyCharacterType() || DestTy->isVoidType() ||
SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) {
return;
}
// or one of the types is a tag type.
if (SrcTy->getAs<TagType>() || DestTy->getAs<TagType>()) {
return;
}
// FIXME: Scoped enums?
if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) ||
(SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) {
if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) {
return;
}
}
Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range;
}
static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
QualType DestType) {
QualType SrcType = SrcExpr.get()->getType();
if (Self.Context.hasSameType(SrcType, DestType))
return;
if (const PointerType *SrcPtrTy = SrcType->getAs<PointerType>())
if (SrcPtrTy->isObjCSelType()) {
QualType DT = DestType;
if (isa<PointerType>(DestType))
DT = DestType->getPointeeType();
if (!DT.getUnqualifiedType()->isVoidType())
Self.Diag(SrcExpr.get()->getExprLoc(),
diag::warn_cast_pointer_from_sel)
<< SrcType << DestType << SrcExpr.get()->getSourceRange();
}
}
static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
const Expr *SrcExpr, QualType DestType,
Sema &Self) {
QualType SrcType = SrcExpr->getType();
// Not warning on reinterpret_cast, boolean, constant expressions, etc
// are not explicit design choices, but consistent with GCC's behavior.
// Feel free to modify them if you've reason/evidence for an alternative.
if (CStyle && SrcType->isIntegralType(Self.Context)
&& !SrcType->isBooleanType()
&& !SrcType->isEnumeralType()
&& !SrcExpr->isIntegerConstantExpr(Self.Context)
&& Self.Context.getTypeSize(DestType) >
Self.Context.getTypeSize(SrcType)) {
// Separate between casts to void* and non-void* pointers.
// Some APIs use (abuse) void* for something like a user context,
// and often that value is an integer even if it isn't a pointer itself.
// Having a separate warning flag allows users to control the warning
// for their workflow.
unsigned Diag = DestType->isVoidPointerType() ?
diag::warn_int_to_void_pointer_cast
: diag::warn_int_to_pointer_cast;
Self.Diag(Loc, Diag) << SrcType << DestType;
}
}
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
2009-09-26 08:12:34 +08:00
unsigned &msg,
CastKind &Kind) {
bool IsLValueCast = false;
DestType = Self.Context.getCanonicalType(DestType);
QualType SrcType = SrcExpr.get()->getType();
// Is the source an overloaded name? (i.e. &foo)
// If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ...
if (SrcType == Self.Context.OverloadTy) {
// ... unless foo<int> resolves to an lvalue unambiguously.
// TODO: what if this fails because of DiagnoseUseOfDecl or something
// like it?
ExprResult SingleFunctionExpr = SrcExpr;
if (Self.ResolveAndFixSingleFunctionTemplateSpecialization(
SingleFunctionExpr,
Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
) && SingleFunctionExpr.isUsable()) {
SrcExpr = SingleFunctionExpr;
SrcType = SrcExpr.get()->getType();
} else {
return TC_NotApplicable;
}
}
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
if (!SrcExpr.get()->isGLValue()) {
// Cannot cast non-glvalue to (lvalue or rvalue) reference type. See the
// similar comment in const_cast.
msg = diag::err_bad_cxx_cast_rvalue;
return TC_NotApplicable;
}
if (!CStyle) {
Self.CheckCompatibleReinterpretCast(SrcType, DestType,
/*isDereference=*/false, OpRange);
}
// C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
// same effect as the conversion *reinterpret_cast<T*>(&x) with the
// built-in & and * operators.
const char *inappropriate = nullptr;
switch (SrcExpr.get()->getObjectKind()) {
2011-04-23 09:10:24 +08:00
case OK_Ordinary:
break;
case OK_BitField: inappropriate = "bit-field"; break;
case OK_VectorComponent: inappropriate = "vector element"; break;
case OK_ObjCProperty: inappropriate = "property expression"; break;
case OK_ObjCSubscript: inappropriate = "container subscripting expression";
break;
}
if (inappropriate) {
Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_reference)
<< inappropriate << DestType
<< OpRange << SrcExpr.get()->getSourceRange();
msg = 0; SrcExpr = ExprError();
return TC_NotApplicable;
}
// This code does this transformation for the checked types.
DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
SrcType = Self.Context.getPointerType(SrcType);
IsLValueCast = true;
}
// Canonicalize source for comparison.
SrcType = Self.Context.getCanonicalType(SrcType);
const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(),
*SrcMemPtr = SrcType->getAs<MemberPointerType>();
if (DestMemPtr && SrcMemPtr) {
// C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
// can be explicitly converted to an rvalue of type "pointer to member
// of Y of type T2" if T1 and T2 are both function types or both object
// types.
if (DestMemPtr->getPointeeType()->isFunctionType() !=
SrcMemPtr->getPointeeType()->isFunctionType())
return TC_NotApplicable;
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
// constness.
// A reinterpret_cast followed by a const_cast can, though, so in C-style,
// we accept it.
if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
/*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// We need to determine the inheritance model that the class will use if
// haven't yet.
Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0);
Self.RequireCompleteType(OpRange.getBegin(), DestType, 0);
}
// Don't allow casting between member pointers of different sizes.
if (Self.Context.getTypeSize(DestMemPtr) !=
Self.Context.getTypeSize(SrcMemPtr)) {
msg = diag::err_bad_cxx_cast_member_pointer_size;
return TC_Failed;
}
// A valid member pointer cast.
assert(!IsLValueCast);
Kind = CK_ReinterpretMemberPointer;
return TC_Success;
}
// See below for the enumeral issue.
if (SrcType->isNullPtrType() && DestType->isIntegralType(Self.Context)) {
// C++0x 5.2.10p4: A pointer can be explicitly converted to any integral
// type large enough to hold it. A value of std::nullptr_t can be
// converted to an integral type; the conversion has the same meaning
// and validity as a conversion of (void*)0 to the integral type.
if (Self.Context.getTypeSize(SrcType) >
Self.Context.getTypeSize(DestType)) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
Kind = CK_PointerToIntegral;
return TC_Success;
}
bool destIsVector = DestType->isVectorType();
bool srcIsVector = SrcType->isVectorType();
if (srcIsVector || destIsVector) {
// FIXME: Should this also apply to floating point types?
bool srcIsScalar = SrcType->isIntegralType(Self.Context);
bool destIsScalar = DestType->isIntegralType(Self.Context);
// Check if this is a cast between a vector and something else.
if (!(srcIsScalar && destIsVector) && !(srcIsVector && destIsScalar) &&
!(srcIsVector && destIsVector))
return TC_NotApplicable;
// If both types have the same size, we can successfully cast.
if (Self.Context.getTypeSize(SrcType)
== Self.Context.getTypeSize(DestType)) {
Kind = CK_BitCast;
return TC_Success;
}
if (destIsScalar)
msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size;
else if (srcIsScalar)
msg = diag::err_bad_cxx_cast_scalar_to_vector_different_size;
else
msg = diag::err_bad_cxx_cast_vector_to_vector_different_size;
return TC_Failed;
}
if (SrcType == DestType) {
// C++ 5.2.10p2 has a note that mentions that, subject to all other
// restrictions, a cast to the same type is allowed so long as it does not
// cast away constness. In C++98, the intent was not entirely clear here,
// since all other paragraphs explicitly forbid casts to the same type.
// C++11 clarifies this case with p2.
//
// The only allowed types are: integral, enumeration, pointer, or
// pointer-to-member types. We also won't restrict Obj-C pointers either.
Kind = CK_NoOp;
TryCastResult Result = TC_NotApplicable;
if (SrcType->isIntegralOrEnumerationType() ||
SrcType->isAnyPointerType() ||
SrcType->isMemberPointerType() ||
SrcType->isBlockPointerType()) {
Result = TC_Success;
}
return Result;
}
bool destIsPtr = DestType->isAnyPointerType() ||
DestType->isBlockPointerType();
bool srcIsPtr = SrcType->isAnyPointerType() ||
SrcType->isBlockPointerType();
if (!destIsPtr && !srcIsPtr) {
// Except for std::nullptr_t->integer and lvalue->reference, which are
// handled above, at least one of the two arguments must be a pointer.
return TC_NotApplicable;
}
if (DestType->isIntegralType(Self.Context)) {
assert(srcIsPtr && "One type must be a pointer");
// C++ 5.2.10p4: A pointer can be explicitly converted to any integral
// type large enough to hold it; except in Microsoft mode, where the
// integral type size doesn't matter (except we don't allow bool).
bool MicrosoftException = Self.getLangOpts().MicrosoftExt &&
!DestType->isBooleanType();
if ((Self.Context.getTypeSize(SrcType) >
Self.Context.getTypeSize(DestType)) &&
!MicrosoftException) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
Kind = CK_PointerToIntegral;
return TC_Success;
}
if (SrcType->isIntegralOrEnumerationType()) {
assert(destIsPtr && "One type must be a pointer");
checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType,
Self);
// C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
// converted to a pointer.
// C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not
// necessarily converted to a null pointer value.]
Kind = CK_IntegralToPointer;
return TC_Success;
}
if (!destIsPtr || !srcIsPtr) {
// With the valid non-pointer conversions out of the way, we can be even
// more stringent.
return TC_NotApplicable;
}
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
// The C-style cast operator can.
if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
/*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
// Cannot convert between block pointers and Objective-C object pointers.
if ((SrcType->isBlockPointerType() && DestType->isObjCObjectPointerType()) ||
(DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType()))
return TC_NotApplicable;
if (IsLValueCast) {
Kind = CK_LValueBitCast;
} else if (DestType->isObjCObjectPointerType()) {
Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr);
} else if (DestType->isBlockPointerType()) {
if (!SrcType->isBlockPointerType()) {
Kind = CK_AnyPointerToBlockPointerCast;
} else {
Kind = CK_BitCast;
}
} else {
Kind = CK_BitCast;
}
// Any pointer can be cast to an Objective-C pointer type with a C-style
// cast.
if (CStyle && DestType->isObjCObjectPointerType()) {
return TC_Success;
}
if (CStyle)
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
// Not casting away constness, so the only remaining check is for compatible
// pointer categories.
if (SrcType->isFunctionPointerType()) {
if (DestType->isFunctionPointerType()) {
// C++ 5.2.10p6: A pointer to a function can be explicitly converted to
// a pointer to a function of a different type.
return TC_Success;
}
// C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
// an object type or vice versa is conditionally-supported.
// Compilers support it in C++03 too, though, because it's necessary for
// casting the return value of dlsym() and GetProcAddress().
// FIXME: Conditionally-supported behavior should be configurable in the
// TargetInfo or similar.
Self.Diag(OpRange.getBegin(),
Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
return TC_Success;
}
if (DestType->isFunctionPointerType()) {
// See above.
Self.Diag(OpRange.getBegin(),
Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
return TC_Success;
}
// C++ 5.2.10p7: A pointer to an object can be explicitly converted to
// a pointer to an object of different type.
// Void pointers are not specified, but supported by every compiler out there.
// So we finish by allowing everything that remains - it's got to be two
// object pointers.
return TC_Success;
}
void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
bool ListInitialization) {
// Handle placeholders.
if (isPlaceholder()) {
// C-style casts can resolve __unknown_any types.
if (claimPlaceholder(BuiltinType::UnknownAny)) {
SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType,
SrcExpr.get(), Kind,
ValueKind, BasePath);
return;
}
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid())
return;
}
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
if (DestType->isVoidType()) {
Kind = CK_ToVoid;
if (claimPlaceholder(BuiltinType::Overload)) {
Self.ResolveAndFixSingleFunctionTemplateSpecialization(
SrcExpr, /* Decay Function to ptr */ false,
/* Complain */ true, DestRange, DestType,
diag::err_bad_cstyle_cast_overload);
if (SrcExpr.isInvalid())
return;
}
SrcExpr = Self.IgnoredValueConversions(SrcExpr.get());
return;
}
// If the type is dependent, we won't do any other semantic analysis now.
if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent() ||
SrcExpr.get()->isValueDependent()) {
assert(Kind == CK_Dependent);
return;
}
if (ValueKind == VK_RValue && !DestType->isRecordType() &&
!isPlaceholder(BuiltinType::Overload)) {
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
}
// AltiVec vector initialization with a single literal.
if (const VectorType *vecTy = DestType->getAs<VectorType>())
if (vecTy->getVectorKind() == VectorType::AltiVecVector
&& (SrcExpr.get()->getType()->isIntegerType()
|| SrcExpr.get()->getType()->isFloatingType())) {
Kind = CK_VectorSplat;
return;
}
// C++ [expr.cast]p5: The conversions performed by
// - a const_cast,
// - a static_cast,
// - a static_cast followed by a const_cast,
// - a reinterpret_cast, or
// - a reinterpret_cast followed by a const_cast,
// can be performed using the cast notation of explicit type conversion.
// [...] If a conversion can be interpreted in more than one of the ways
// listed above, the interpretation that appears first in the list is used,
// even if a cast resulting from that interpretation is ill-formed.
// In plain language, this means trying a const_cast ...
unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType,
/*CStyle*/true, msg);
if (SrcExpr.isInvalid())
return;
if (tcr == TC_Success)
Kind = CK_NoOp;
Sema::CheckedConversionKind CCK
= FunctionalStyle? Sema::CCK_FunctionalCast
: Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange,
msg, Kind, BasePath, ListInitialization);
if (SrcExpr.isInvalid())
return;
if (tcr == TC_NotApplicable) {
// ... and finally a reinterpret_cast, ignoring const.
tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true,
OpRange, msg, Kind);
if (SrcExpr.isInvalid())
return;
}
}
if (Self.getLangOpts().ObjCAutoRefCount && tcr == TC_Success)
checkObjCARCConversion(CCK);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
DeclAccessPair Found;
FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
DestType,
/*Complain*/ true,
Found);
if (Fn) {
// If DestType is a function type (not to be confused with the function
// pointer type), it will be possible to resolve the function address,
// but the type cast should be considered as failure.
OverloadExpr *OE = OverloadExpr::find(SrcExpr.get()).Expression;
Self.Diag(OpRange.getBegin(), diag::err_bad_cstyle_cast_overload)
<< OE->getName() << DestType << OpRange
<< OE->getQualifierLoc().getSourceRange();
Self.NoteAllOverloadCandidates(SrcExpr.get());
}
} else {
diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
OpRange, SrcExpr.get(), DestType, ListInitialization);
}
} else if (Kind == CK_BitCast) {
checkCastAlign();
}
// Clear out SrcExpr if there was a fatal error.
if (tcr != TC_Success)
SrcExpr = ExprError();
}
/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a
/// non-matching type. Such as enum function call to int, int call to
/// pointer; etc. Cast to 'void' is an exception.
static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr,
QualType DestType) {
if (Self.Diags.isIgnored(diag::warn_bad_function_cast,
SrcExpr.get()->getExprLoc()))
return;
if (!isa<CallExpr>(SrcExpr.get()))
return;
QualType SrcType = SrcExpr.get()->getType();
if (DestType.getUnqualifiedType()->isVoidType())
return;
if ((SrcType->isAnyPointerType() || SrcType->isBlockPointerType())
&& (DestType->isAnyPointerType() || DestType->isBlockPointerType()))
return;
if (SrcType->isIntegerType() && DestType->isIntegerType() &&
(SrcType->isBooleanType() == DestType->isBooleanType()) &&
(SrcType->isEnumeralType() == DestType->isEnumeralType()))
return;
if (SrcType->isRealFloatingType() && DestType->isRealFloatingType())
return;
if (SrcType->isEnumeralType() && DestType->isEnumeralType())
return;
if (SrcType->isComplexType() && DestType->isComplexType())
return;
if (SrcType->isComplexIntegerType() && DestType->isComplexIntegerType())
return;
Self.Diag(SrcExpr.get()->getExprLoc(),
diag::warn_bad_function_cast)
<< SrcType << DestType << SrcExpr.get()->getSourceRange();
}
/// Check the semantics of a C-style cast operation, in C.
void CastOperation::CheckCStyleCast() {
assert(!Self.getLangOpts().CPlusPlus);
// C-style casts can resolve __unknown_any types.
if (claimPlaceholder(BuiltinType::UnknownAny)) {
SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType,
SrcExpr.get(), Kind,
ValueKind, BasePath);
return;
}
// C99 6.5.4p2: the cast type needs to be void or scalar and the expression
// type needs to be scalar.
if (DestType->isVoidType()) {
// We don't necessarily do lvalue-to-rvalue conversions on this.
SrcExpr = Self.IgnoredValueConversions(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
// Cast to void allows any expr type.
Kind = CK_ToVoid;
return;
}
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
QualType SrcType = SrcExpr.get()->getType();
assert(!SrcType->isPlaceholderType());
// OpenCL v1 s6.5: Casting a pointer to address space A to a pointer to
// address space B is illegal.
if (Self.getLangOpts().OpenCL && DestType->isPointerType() &&
SrcType->isPointerType()) {
if (DestType->getPointeeType().getAddressSpace() !=
SrcType->getPointeeType().getAddressSpace()) {
Self.Diag(OpRange.getBegin(),
diag::err_typecheck_incompatible_address_space)
<< SrcType << DestType << Sema::AA_Casting
<< SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
}
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_typecheck_cast_to_incomplete)) {
SrcExpr = ExprError();
return;
}
if (!DestType->isScalarType() && !DestType->isVectorType()) {
const RecordType *DestRecordTy = DestType->getAs<RecordType>();
if (DestRecordTy && Self.Context.hasSameUnqualifiedType(DestType, SrcType)){
// GCC struct/union extension: allow cast to self.
Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar)
<< DestType << SrcExpr.get()->getSourceRange();
Kind = CK_NoOp;
return;
}
// GCC's cast to union extension.
if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) {
RecordDecl *RD = DestRecordTy->getDecl();
RecordDecl::field_iterator Field, FieldEnd;
for (Field = RD->field_begin(), FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) &&
!Field->isUnnamedBitfield()) {
Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union)
<< SrcExpr.get()->getSourceRange();
break;
}
}
if (Field == FieldEnd) {
Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type)
<< SrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
Kind = CK_ToUnion;
return;
}
// Reject any other conversions to non-scalar types.
Self.Diag(OpRange.getBegin(), diag::err_typecheck_cond_expect_scalar)
<< DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
// The type we're casting to is known to be a scalar or vector.
// Require the operand to be a scalar or vector.
if (!SrcType->isScalarType() && !SrcType->isVectorType()) {
Self.Diag(SrcExpr.get()->getExprLoc(),
diag::err_typecheck_expect_scalar_operand)
<< SrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
if (DestType->isExtVectorType()) {
SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.get(), Kind);
return;
}
if (const VectorType *DestVecTy = DestType->getAs<VectorType>()) {
if (DestVecTy->getVectorKind() == VectorType::AltiVecVector &&
(SrcType->isIntegerType() || SrcType->isFloatingType())) {
Kind = CK_VectorSplat;
} else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) {
SrcExpr = ExprError();
}
return;
}
if (SrcType->isVectorType()) {
if (Self.CheckVectorCast(OpRange, SrcType, DestType, Kind))
SrcExpr = ExprError();
return;
}
// The source and target types are both scalars, i.e.
// - arithmetic types (fundamental, enum, and complex)
// - all kinds of pointers
// Note that member pointers were filtered out with C++, above.
if (isa<ObjCSelectorExpr>(SrcExpr.get())) {
Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_selector_expr);
SrcExpr = ExprError();
return;
}
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
if (!DestType->isArithmeticType()) {
if (!SrcType->isIntegralType(Self.Context) && SrcType->isArithmeticType()) {
Self.Diag(SrcExpr.get()->getExprLoc(),
diag::err_cast_pointer_from_non_pointer_int)
<< SrcType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
DestType, Self);
} else if (!SrcType->isArithmeticType()) {
if (!DestType->isIntegralType(Self.Context) &&
DestType->isArithmeticType()) {
Self.Diag(SrcExpr.get()->getLocStart(),
diag::err_cast_pointer_to_non_pointer_int)
<< DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
}
if (Self.getLangOpts().OpenCL && !Self.getOpenCLOptions().cl_khr_fp16) {
if (DestType->isHalfType()) {
Self.Diag(SrcExpr.get()->getLocStart(), diag::err_opencl_cast_to_half)
<< DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
}
// ARC imposes extra restrictions on casts.
if (Self.getLangOpts().ObjCAutoRefCount) {
checkObjCARCConversion(Sema::CCK_CStyleCast);
if (SrcExpr.isInvalid())
return;
if (const PointerType *CastPtr = DestType->getAs<PointerType>()) {
if (const PointerType *ExprPtr = SrcType->getAs<PointerType>()) {
Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
ExprPtr->getPointeeType()->isObjCLifetimeType() &&
!CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
Self.Diag(SrcExpr.get()->getLocStart(),
diag::err_typecheck_incompatible_ownership)
<< SrcType << DestType << Sema::AA_Casting
<< SrcExpr.get()->getSourceRange();
return;
}
}
}
else if (!Self.CheckObjCARCUnavailableWeakConversion(DestType, SrcType)) {
Self.Diag(SrcExpr.get()->getLocStart(),
diag::err_arc_convesion_of_weak_unavailable)
<< 1 << SrcType << DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
}
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
Kind = Self.PrepareScalarCast(SrcExpr, DestType);
if (SrcExpr.isInvalid())
return;
if (Kind == CK_BitCast)
checkCastAlign();
// -Wcast-qual
QualType TheOffendingSrcType, TheOffendingDestType;
Qualifiers CastAwayQualifiers;
if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() &&
CastsAwayConstness(Self, SrcType, DestType, true, false,
&TheOffendingSrcType, &TheOffendingDestType,
&CastAwayQualifiers)) {
int qualifiers = -1;
if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
qualifiers = 0;
} else if (CastAwayQualifiers.hasConst()) {
qualifiers = 1;
} else if (CastAwayQualifiers.hasVolatile()) {
qualifiers = 2;
}
// This is a variant of int **x; const int **y = (const int **)x;
if (qualifiers == -1)
Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) <<
SrcType << DestType;
else
Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) <<
TheOffendingSrcType << TheOffendingDestType << qualifiers;
}
}
ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
TypeSourceInfo *CastTypeInfo,
SourceLocation RPLoc,
Expr *CastExpr) {
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd());
if (getLangOpts().CPlusPlus) {
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false,
isa<InitListExpr>(CastExpr));
} else {
Op.CheckCStyleCast();
}
if (Op.SrcExpr.isInvalid())
return ExprError();
return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, CastTypeInfo, LPLoc, RPLoc));
}
ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
SourceLocation LPLoc,
Expr *CastExpr,
SourceLocation RPLoc) {
assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false);
if (Op.SrcExpr.isInvalid())
return ExprError();
if (CXXConstructExpr *ConstructExpr = dyn_cast<CXXConstructExpr>(Op.SrcExpr.get()))
ConstructExpr->setParenOrBraceRange(SourceRange(LPLoc, RPLoc));
return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, CastTypeInfo, Op.Kind,
Op.SrcExpr.get(), &Op.BasePath, LPLoc, RPLoc));
}