summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaCXXCast.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaCXXCast.cpp')
-rw-r--r--lib/Sema/SemaCXXCast.cpp150
1 files changed, 91 insertions, 59 deletions
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 76faddaa..e5ad338 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -70,28 +70,31 @@ static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
- unsigned &msg);
+ unsigned &msg,
+ CastExpr::CastKind &Kind);
static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
- unsigned &msg);
-static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType,
- QualType DestType, bool CStyle,
+ unsigned &msg,
+ CastExpr::CastKind &Kind);
+static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
+ CanQualType DestType, bool CStyle,
const SourceRange &OpRange,
QualType OrigSrcType,
- QualType OrigDestType, unsigned &msg);
+ QualType OrigDestType, unsigned &msg,
+ CastExpr::CastKind &Kind);
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType,
QualType DestType,bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind);
-static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl);
-static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
@@ -187,7 +190,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
"Destination type is not pointer or pointer to member.");
- QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType;
+ QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
+ UnwrappedDestType = Self.Context.getCanonicalType(DestType);
llvm::SmallVector<Qualifiers, 8> cv1, cv2;
// Find the qualifications.
@@ -385,14 +389,15 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// 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 = CastExpr::CK_ToVoid;
return;
}
- if (!DestType->isLValueReferenceType())
+ if (!DestType->isLValueReferenceType() && !DestType->isRecordType())
Self.DefaultFunctionArrayConversion(SrcExpr);
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg,
+ if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
Kind, ConversionDecl)
!= TC_Success && msg != 0)
Self.Diag(OpRange.getBegin(), msg) << CT_Static
@@ -402,7 +407,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/// 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, Expr *SrcExpr,
+static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
@@ -427,15 +432,18 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
// 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, DestType, CStyle,OpRange,msg);
+ tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange,
+ msg, Kind);
if (tcr != TC_NotApplicable)
return tcr;
// N2844 5.2.9p3: An lvalue 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, DestType, msg);
- if (tcr != TC_NotApplicable)
+ if (tcr != TC_NotApplicable) {
+ Kind = CastExpr::CK_NoOp;
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, [...].
@@ -467,13 +475,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
if (DestType->isEnumeralType()) {
if (SrcType->isComplexType() || SrcType->isVectorType()) {
// Fall through - these cannot be converted.
- } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType())
+ } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) {
+ Kind = CastExpr::CK_IntegralCast;
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);
+ tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
+ Kind);
if (tcr != TC_NotApplicable)
return tcr;
@@ -500,6 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr,
msg = diag::err_bad_cxx_cast_const_away;
return TC_Failed;
}
+ Kind = CastExpr::CK_BitCast;
return TC_Success;
}
}
@@ -544,7 +556,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
TryCastResult
TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg) {
+ unsigned &msg, CastExpr::CastKind &Kind) {
// 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"
@@ -567,15 +579,17 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
QualType DestPointee = DestReference->getPointeeType();
- return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, CStyle,
- OpRange, SrcExpr->getType(), DestType, msg);
+ return TryStaticDowncast(Self,
+ Self.Context.getCanonicalType(SrcExpr->getType()),
+ Self.Context.getCanonicalType(DestPointee), CStyle,
+ OpRange, SrcExpr->getType(), DestType, msg, Kind);
}
/// 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) {
+ unsigned &msg, CastExpr::CastKind &Kind) {
// 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
@@ -595,25 +609,27 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TC_NotApplicable;
}
- return TryStaticDowncast(Self, SrcPointer->getPointeeType(),
- DestPointer->getPointeeType(), CStyle,
- OpRange, SrcType, DestType, msg);
+ return TryStaticDowncast(Self,
+ Self.Context.getCanonicalType(SrcPointer->getPointeeType()),
+ Self.Context.getCanonicalType(DestPointer->getPointeeType()),
+ CStyle, OpRange, SrcType, DestType, msg, Kind);
}
/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to
-/// DestType, both of which must be canonical, is possible and allowed.
+/// DestType is possible and allowed.
TryCastResult
-TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
+TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
- QualType OrigDestType, unsigned &msg) {
+ QualType OrigDestType, unsigned &msg,
+ CastExpr::CastKind &Kind) {
// We can only work with complete types. But don't complain if it doesn't work
if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) ||
Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0)))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
- if (!DestType->isRecordType() || !SrcType->isRecordType()) {
+ if (!DestType->getAs<RecordType>() || !SrcType->getAs<RecordType>()) {
return TC_NotApplicable;
}
@@ -669,12 +685,13 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
EE = PI->rend();
EI != EE; ++EI)
PathDisplayStr += EI->Base->getType().getAsString() + " -> ";
- PathDisplayStr += DestType.getAsString();
+ PathDisplayStr += QualType(DestType).getAsString();
}
}
Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
- << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType()
+ << QualType(SrcType).getUnqualifiedType()
+ << QualType(DestType).getUnqualifiedType()
<< PathDisplayStr << OpRange;
msg = 0;
return TC_Failed;
@@ -695,6 +712,7 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TC_Failed;
}
+ Kind = CastExpr::CK_BaseToDerived;
return TC_Success;
}
@@ -719,10 +737,8 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
}
// T == T, modulo cv
- if (Self.Context.getCanonicalType(
- SrcMemPtr->getPointeeType().getUnqualifiedType()) !=
- Self.Context.getCanonicalType(DestMemPtr->getPointeeType().
- getUnqualifiedType()))
+ if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(),
+ DestMemPtr->getPointeeType()))
return TC_NotApplicable;
// B base of D
@@ -772,7 +788,7 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
/// 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, Expr *SrcExpr, QualType DestType,
+TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
CXXMethodDecl *&ConversionDecl) {
@@ -785,27 +801,49 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
}
if (DestType->isReferenceType()) {
+ // All reference bindings insert implicit casts above that do the actual
+ // casting.
+ Kind = CastExpr::CK_NoOp;
+
// At this point of CheckStaticCast, if the destination is a reference,
// 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. In that case, we pass an ICS so we don't
- // get error messages.
- ImplicitConversionSequence ICS;
- bool failed = Self.CheckReferenceInit(SrcExpr, DestType,
- OpRange.getBegin(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- CStyle ? &ICS : 0);
- if (!failed)
+ // the reinterpret_cast way. So in C-style mode, we first try the call
+ // with an ICS to suppress errors.
+ if (CStyle) {
+ ImplicitConversionSequence ICS;
+ if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false, /*ForceRValue=*/false,
+ &ICS))
+ return TC_NotApplicable;
+ }
+ // Now we're committed either way.
+ if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*ForceRValue=*/false, 0,
+ /*IgnoreBaseAccess=*/CStyle))
return TC_Success;
- if (CStyle)
- return TC_NotApplicable;
- // If we didn't pass the ICS, we already got an error message.
+
+ // We already got an error message.
msg = 0;
return TC_Failed;
}
+ if (DestType->isRecordType()) {
+ if (CXXConstructorDecl *Constructor
+ = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
+ OpRange.getBegin(),
+ Sema::IK_Direct)) {
+ ConversionDecl = Constructor;
+ Kind = CastExpr::CK_ConstructorConversion;
+ return TC_Success;
+ }
+
+ return TC_NotApplicable;
+ }
+
// FIXME: To get a proper error from invalid conversions here, we need to
// reimplement more of this.
// FIXME: This does not actually perform the conversion, and thus does not
@@ -821,18 +859,12 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType,
if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
return TC_NotApplicable;
- if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) {
- ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction);
- if (isa<CXXConstructorDecl>(ConversionDecl))
- Kind = CastExpr::CK_ConstructorConversion;
- else if (isa<CXXConversionDecl>(ConversionDecl))
- Kind = CastExpr::CK_UserDefinedConversion;
- } else if (ICS.ConversionKind ==
- ImplicitConversionSequence::StandardConversion) {
- // FIXME: Set the cast kind depending on which types of conversions we have.
- }
-
- return TC_Success;
+ // The conversion is possible, so commit to it.
+ Kind = CastExpr::CK_NoOp;
+ msg = 0;
+ return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, "casting",
+ /*IgnoreBaseAccess*/CStyle) ?
+ TC_Failed : TC_Success;
}
/// TryConstCast - See if a const_cast from source to destination is allowed,
@@ -1104,7 +1136,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
if (CastTy->isDependentType() || CastExpr->isTypeDependent())
return false;
- if (!CastTy->isLValueReferenceType())
+ if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType())
DefaultFunctionArrayConversion(CastExpr);
// C++ [expr.cast]p5: The conversions performed by
OpenPOWER on IntegriCloud