summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2019-01-27 16:42:12 +0000
committerpatrick <patrick@openbsd.org>2019-01-27 16:42:12 +0000
commitb773203fb58f3ef282fb69c832d8710cab5bc82d (patch)
treee75913f147570fbd75169647b144df85b88a038c /gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp
parenttweak errno in previous (diff)
downloadwireguard-openbsd-b773203fb58f3ef282fb69c832d8710cab5bc82d.tar.xz
wireguard-openbsd-b773203fb58f3ef282fb69c832d8710cab5bc82d.zip
Import LLVM 7.0.1 release including clang, lld and lldb.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp')
-rw-r--r--gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp579
1 files changed, 320 insertions, 259 deletions
diff --git a/gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp b/gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp
index ad6348685b6..57aac80f5ad 100644
--- a/gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp
+++ b/gnu/llvm/tools/clang/lib/Sema/SemaCast.cpp
@@ -33,10 +33,16 @@ using namespace clang;
enum TryCastResult {
TC_NotApplicable, ///< The cast method is not applicable.
TC_Success, ///< The cast method is appropriate and successful.
+ TC_Extension, ///< The cast method is appropriate and accepted as a
+ ///< language extension.
TC_Failed ///< The cast method is appropriate, but failed. A
///< diagnostic has been emitted.
};
+static bool isValidCast(TryCastResult TCR) {
+ return TCR == TC_Success || TCR == TC_Extension;
+}
+
enum CastType {
CT_Const, ///< const_cast
CT_Static, ///< static_cast
@@ -83,6 +89,14 @@ namespace {
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
+ void updatePartOfExplicitCastFlags(CastExpr *CE) {
+ // Walk down from the CE to the OrigSrcExpr, and mark all immediate
+ // ImplicitCastExpr's as being part of ExplicitCastExpr. The original CE
+ // (which is a ExplicitCastExpr), and the OrigSrcExpr are not touched.
+ for (; auto *ICE = dyn_cast<ImplicitCastExpr>(CE->getSubExpr()); CE = ICE)
+ ICE->setIsPartOfExplicitCast(true);
+ }
+
/// Complete an apparently-successful cast operation that yields
/// the given expression.
ExprResult complete(CastExpr *castExpr) {
@@ -94,6 +108,7 @@ namespace {
CK_Dependent, castExpr, nullptr,
castExpr->getValueKind());
}
+ updatePartOfExplicitCastFlags(castExpr);
return castExpr;
}
@@ -190,13 +205,13 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp
CXXCastPath &BasePath);
static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType,
+ QualType DestType,
Sema::CheckedConversionKind CCK,
SourceRange OpRange,
unsigned &msg, CastKind &Kind,
bool ListInitialization);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType,
+ QualType DestType,
Sema::CheckedConversionKind CCK,
SourceRange OpRange,
unsigned &msg, CastKind &Kind,
@@ -267,6 +282,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
AngleBrackets));
case tok::kw_dynamic_cast: {
+ // OpenCL C++ 1.0 s2.9: dynamic_cast is not supported.
+ if (getLangOpts().OpenCLCPlusPlus) {
+ return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported)
+ << "dynamic_cast");
+ }
+
if (!TypeDependent) {
Op.CheckDynamicCast();
if (Op.SrcExpr.isInvalid())
@@ -298,7 +319,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return ExprError();
DiscardMisalignedMemberAddress(DestType.getTypePtr(), E);
}
-
+
return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, DestTInfo,
@@ -425,95 +446,114 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
}
}
-/// 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.
-/// And additionally, it handles C++ references. If both the types are
-/// references, then their pointee types are returned,
-/// else if only one of them is reference, it's pointee type is returned,
-/// and the other type is returned as-is.
-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;
- }
-
- const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(),
- *T2RefType = T2->getAs<LValueReferenceType>();
- if (T1RefType && T2RefType) {
- T1 = T1RefType->getPointeeType();
- T2 = T2RefType->getPointeeType();
- return true;
- }
+namespace {
+/// The kind of unwrapping we did when determining whether a conversion casts
+/// away constness.
+enum CastAwayConstnessKind {
+ /// The conversion does not cast away constness.
+ CACK_None = 0,
+ /// We unwrapped similar types.
+ CACK_Similar = 1,
+ /// We unwrapped dissimilar types with similar representations (eg, a pointer
+ /// versus an Objective-C object pointer).
+ CACK_SimilarKind = 2,
+ /// We unwrapped representationally-unrelated types, such as a pointer versus
+ /// a pointer-to-member.
+ CACK_Incoherent = 3,
+};
+}
- if (T1RefType) {
- T1 = T1RefType->getPointeeType();
- // T2 = T2;
- return true;
+/// Unwrap one level of types for CastsAwayConstness.
+///
+/// Like Sema::UnwrapSimilarTypes, this removes one level of indirection from
+/// both types, provided that they're both pointer-like or array-like. Unlike
+/// the Sema function, doesn't care if the unwrapped pieces are related.
+///
+/// This function may remove additional levels as necessary for correctness:
+/// the resulting T1 is unwrapped sufficiently that it is never an array type,
+/// so that its qualifiers can be directly compared to those of T2 (which will
+/// have the combined set of qualifiers from all indermediate levels of T2),
+/// as (effectively) required by [expr.const.cast]p7 replacing T1's qualifiers
+/// with those from T2.
+static CastAwayConstnessKind
+unwrapCastAwayConstnessLevel(ASTContext &Context, QualType &T1, QualType &T2) {
+ enum { None, Ptr, MemPtr, BlockPtr, Array };
+ auto Classify = [](QualType T) {
+ if (T->isAnyPointerType()) return Ptr;
+ if (T->isMemberPointerType()) return MemPtr;
+ if (T->isBlockPointerType()) return BlockPtr;
+ // We somewhat-arbitrarily don't look through VLA types here. This is at
+ // least consistent with the behavior of UnwrapSimilarTypes.
+ if (T->isConstantArrayType() || T->isIncompleteArrayType()) return Array;
+ return None;
+ };
+
+ auto Unwrap = [&](QualType T) {
+ if (auto *AT = Context.getAsArrayType(T))
+ return AT->getElementType();
+ return T->getPointeeType();
+ };
+
+ CastAwayConstnessKind Kind;
+
+ if (T2->isReferenceType()) {
+ // Special case: if the destination type is a reference type, unwrap it as
+ // the first level. (The source will have been an lvalue expression in this
+ // case, so there is no corresponding "reference to" in T1 to remove.) This
+ // simulates removing a "pointer to" from both sides.
+ T2 = T2->getPointeeType();
+ Kind = CastAwayConstnessKind::CACK_Similar;
+ } else if (Context.UnwrapSimilarTypes(T1, T2)) {
+ Kind = CastAwayConstnessKind::CACK_Similar;
+ } else {
+ // Try unwrapping mismatching levels.
+ int T1Class = Classify(T1);
+ if (T1Class == None)
+ return CastAwayConstnessKind::CACK_None;
+
+ int T2Class = Classify(T2);
+ if (T2Class == None)
+ return CastAwayConstnessKind::CACK_None;
+
+ T1 = Unwrap(T1);
+ T2 = Unwrap(T2);
+ Kind = T1Class == T2Class ? CastAwayConstnessKind::CACK_SimilarKind
+ : CastAwayConstnessKind::CACK_Incoherent;
}
- if (T2RefType) {
- // T1 = T1;
- T2 = T2RefType->getPointeeType();
- return true;
+ // We've unwrapped at least one level. If the resulting T1 is a (possibly
+ // multidimensional) array type, any qualifier on any matching layer of
+ // T2 is considered to correspond to T1. Decompose down to the element
+ // type of T1 so that we can compare properly.
+ while (true) {
+ Context.UnwrapSimilarArrayTypes(T1, T2);
+
+ if (Classify(T1) != Array)
+ break;
+
+ auto T2Class = Classify(T2);
+ if (T2Class == None)
+ break;
+
+ if (T2Class != Array)
+ Kind = CastAwayConstnessKind::CACK_Incoherent;
+ else if (Kind != CastAwayConstnessKind::CACK_Incoherent)
+ Kind = CastAwayConstnessKind::CACK_SimilarKind;
+
+ T1 = Unwrap(T1);
+ T2 = Unwrap(T2).withCVRQualifiers(T2.getCVRQualifiers());
}
- return false;
+ return Kind;
}
-/// 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.
+/// Check if the pointer conversion from SrcType to DestType casts away
+/// constness as defined in C++ [expr.const.cast]. 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
+static CastAwayConstnessKind
CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
bool CheckCVR, bool CheckObjCLifetime,
QualType *TheOffendingSrcType = nullptr,
@@ -521,33 +561,35 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
Qualifiers *CastAwayQualifiers = nullptr) {
// If the only checking we care about is for Objective-C lifetime qualifiers,
// and we're not in ObjC mode, there's nothing to check.
- if (!CheckCVR && CheckObjCLifetime &&
- !Self.Context.getLangOpts().ObjC1)
- 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() ||
- DestType->isLValueReferenceType()) &&
- "Source type is not pointer or pointer to member.");
- assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() ||
- DestType->isBlockPointerType() ||
- DestType->isLValueReferenceType()) &&
- "Destination type is not pointer or pointer to member, or reference.");
-
- QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
+ if (!CheckCVR && CheckObjCLifetime && !Self.Context.getLangOpts().ObjC1)
+ return CastAwayConstnessKind::CACK_None;
+
+ if (!DestType->isReferenceType()) {
+ 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,
+ // 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)) {
+ auto WorstKind = CastAwayConstnessKind::CACK_Similar;
+ bool AllConstSoFar = true;
+ while (auto Kind = unwrapCastAwayConstnessLevel(
+ Self.Context, UnwrappedSrcType, UnwrappedDestType)) {
+ // Track the worst kind of unwrap we needed to do before we found a
+ // problem.
+ if (Kind > WorstKind)
+ WorstKind = Kind;
+
// Determine the relevant qualifiers at this level.
Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
@@ -560,51 +602,71 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
UnwrappedDestType->isObjCObjectType())
SrcQuals.removeConst();
- Qualifiers RetainedSrcQuals, RetainedDestQuals;
if (CheckCVR) {
- RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
- RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
+ Qualifiers SrcCvrQuals =
+ Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers());
+ Qualifiers DestCvrQuals =
+ Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers());
+
+ if (SrcCvrQuals != DestCvrQuals) {
+ if (CastAwayQualifiers)
+ *CastAwayQualifiers = SrcCvrQuals - DestCvrQuals;
+
+ // If we removed a cvr-qualifier, this is casting away 'constness'.
+ if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) {
+ if (TheOffendingSrcType)
+ *TheOffendingSrcType = PrevUnwrappedSrcType;
+ if (TheOffendingDestType)
+ *TheOffendingDestType = PrevUnwrappedDestType;
+ return WorstKind;
+ }
- if (RetainedSrcQuals != RetainedDestQuals && TheOffendingSrcType &&
- TheOffendingDestType && CastAwayQualifiers) {
- *TheOffendingSrcType = PrevUnwrappedSrcType;
- *TheOffendingDestType = PrevUnwrappedDestType;
- *CastAwayQualifiers = RetainedSrcQuals - RetainedDestQuals;
+ // If any prior level was not 'const', this is also casting away
+ // 'constness'. We noted the outermost type missing a 'const' already.
+ if (!AllConstSoFar)
+ return WorstKind;
}
}
-
+
if (CheckObjCLifetime &&
!DestQuals.compatiblyIncludesObjCLifetime(SrcQuals))
- return true;
-
- cv1.push_back(RetainedSrcQuals);
- cv2.push_back(RetainedDestQuals);
+ return WorstKind;
+
+ // If we found our first non-const-qualified type, this may be the place
+ // where things start to go wrong.
+ if (AllConstSoFar && !DestQuals.hasConst()) {
+ AllConstSoFar = false;
+ if (TheOffendingSrcType)
+ *TheOffendingSrcType = PrevUnwrappedSrcType;
+ if (TheOffendingDestType)
+ *TheOffendingDestType = PrevUnwrappedDestType;
+ }
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);
+ return CastAwayConstnessKind::CACK_None;
+}
+
+static TryCastResult getCastAwayConstnessCastKind(CastAwayConstnessKind CACK,
+ unsigned &DiagID) {
+ switch (CACK) {
+ case CastAwayConstnessKind::CACK_None:
+ llvm_unreachable("did not cast away constness");
+
+ case CastAwayConstnessKind::CACK_Similar:
+ // FIXME: Accept these as an extension too?
+ case CastAwayConstnessKind::CACK_SimilarKind:
+ DiagID = diag::err_bad_cxx_cast_qualifiers_away;
+ return TC_Failed;
+
+ case CastAwayConstnessKind::CACK_Incoherent:
+ DiagID = diag::ext_bad_cxx_cast_qualifiers_away_incoherent;
+ return TC_Extension;
+ }
+
+ llvm_unreachable("unexpected cast away constness kind");
}
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
@@ -657,7 +719,7 @@ void CastOperation::CheckDynamicCast() {
// 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
+ // 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;
@@ -726,7 +788,7 @@ void CastOperation::CheckDynamicCast() {
if (DestRecord &&
Self.IsDerivedFrom(OpRange.getBegin(), SrcPointee, DestPointee)) {
if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
- OpRange.getBegin(), OpRange,
+ OpRange.getBegin(), OpRange,
&BasePath)) {
SrcExpr = ExprError();
return;
@@ -772,12 +834,13 @@ void CastOperation::CheckConstCast() {
return;
unsigned msg = diag::err_bad_cxx_cast_generic;
- if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success
- && msg != 0) {
+ auto TCR = TryConstCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg);
+ if (TCR != TC_Success && msg != 0) {
Self.Diag(OpRange.getBegin(), msg) << CT_Const
<< SrcExpr.get()->getType() << DestType << OpRange;
- SrcExpr = ExprError();
}
+ if (!isValidCast(TCR))
+ SrcExpr = ExprError();
}
/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
@@ -887,16 +950,15 @@ void CastOperation::CheckReinterpretCast() {
return;
unsigned msg = diag::err_bad_cxx_cast_generic;
- TryCastResult tcr =
- TryReinterpretCast(Self, SrcExpr, DestType,
+ TryCastResult tcr =
+ TryReinterpretCast(Self, SrcExpr, DestType,
/*CStyle*/false, OpRange, msg, Kind);
- if (tcr != TC_Success && msg != 0)
- {
+ 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)
+ //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());
@@ -905,11 +967,14 @@ void CastOperation::CheckReinterpretCast() {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(),
DestType, /*listInitialization=*/false);
}
- SrcExpr = ExprError();
- } else if (tcr == TC_Success) {
+ }
+
+ if (isValidCast(tcr)) {
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
checkObjCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
+ } else {
+ SrcExpr = ExprError();
}
}
@@ -931,8 +996,8 @@ void CastOperation::CheckStaticCast() {
Kind = CK_ToVoid;
if (claimPlaceholder(BuiltinType::Overload)) {
- Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr,
- false, // Decay Function to ptr
+ Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr,
+ false, // Decay Function to ptr
true, // Complain
OpRange, DestType, diag::err_bad_static_cast_overload);
if (SrcExpr.isInvalid())
@@ -960,21 +1025,22 @@ void CastOperation::CheckStaticCast() {
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->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 (isValidCast(tcr)) {
if (Kind == CK_BitCast)
checkCastAlign();
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
checkObjCConversion(Sema::CCK_OtherCast);
- } else if (Kind == CK_BitCast) {
- checkCastAlign();
+ } else {
+ SrcExpr = ExprError();
}
}
@@ -982,15 +1048,15 @@ void CastOperation::CheckStaticCast() {
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
- QualType DestType,
+ QualType DestType,
Sema::CheckedConversionKind CCK,
SourceRange OpRange, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath,
bool ListInitialization) {
// Determine whether we have the semantics of a C-style cast.
- bool CStyle
+ 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 {};
@@ -1016,7 +1082,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
if (tcr != TC_NotApplicable)
return tcr;
- // C++11 [expr.static.cast]p3:
+ // C++11 [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,
@@ -1032,7 +1098,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
return TC_Failed;
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.
@@ -1060,7 +1126,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
}
}
}
-
+
// Reverse integral promotion/conversion. All such conversions are themselves
// again integral promotions or conversions and are thus already handled by
// p2 (TryDirectInitialization above).
@@ -1133,7 +1199,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
}
}
else if (DestType->isObjCObjectPointerType()) {
- // allow both c-style cast and static_cast of objective-c pointers as
+ // allow both c-style cast and static_cast of objective-c pointers as
// they are pervasive.
Kind = CK_CPointerToObjCPointerCast;
return TC_Success;
@@ -1145,7 +1211,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
}
}
}
- // Allow arbitray objective-c pointer conversion with static casts.
+ // Allow arbitrary objective-c pointer conversion with static casts.
if (SrcType->isObjCObjectPointerType() &&
DestType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
@@ -1164,7 +1230,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
if (SrcPointer->getPointeeType()->getAs<RecordType>() &&
DestPointer->getPointeeType()->getAs<RecordType>())
msg = diag::err_bad_cxx_cast_unrelated_class;
-
+
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
}
@@ -1218,11 +1284,11 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
if (!Self.IsDerivedFrom(SrcExpr->getLocStart(), SrcExpr->getType(),
R->getPointeeType(), Paths))
return TC_NotApplicable;
-
+
Self.BuildBasePathArray(Paths, BasePath);
} else
Kind = CK_NoOp;
-
+
return TC_Success;
}
@@ -1257,8 +1323,8 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
// 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()),
+ return TryStaticDowncast(Self,
+ Self.Context.getCanonicalType(SrcExpr->getType()),
Self.Context.getCanonicalType(DestPointee), CStyle,
OpRange, SrcExpr->getType(), DestType, msg, Kind,
BasePath);
@@ -1289,9 +1355,9 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TC_NotApplicable;
}
- return TryStaticDowncast(Self,
+ return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcPointer->getPointeeType()),
- Self.Context.getCanonicalType(DestPointer->getPointeeType()),
+ Self.Context.getCanonicalType(DestPointer->getPointeeType()),
CStyle, OpRange, SrcType, DestType, msg, Kind,
BasePath);
}
@@ -1302,7 +1368,7 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
TryCastResult
TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
bool CStyle, SourceRange OpRange, QualType OrigSrcType,
- QualType OrigDestType, unsigned &msg,
+ 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.isCompleteType(OpRange.getBegin(), SrcType) ||
@@ -1368,7 +1434,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
}
Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast)
- << QualType(SrcType).getUnqualifiedType()
+ << QualType(SrcType).getUnqualifiedType()
<< QualType(DestType).getUnqualifiedType()
<< PathDisplayStr << OpRange;
msg = 0;
@@ -1412,8 +1478,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
/// where B is a base class of D [...].
///
TryCastResult
-TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
- QualType DestType, bool CStyle,
+TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
+ QualType DestType, bool CStyle,
SourceRange OpRange,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath) {
@@ -1433,7 +1499,7 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
WasOverloadedFunction = true;
}
}
-
+
const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
if (!SrcMemPtr) {
msg = diag::err_bad_static_cast_member_pointer_nonmp;
@@ -1503,8 +1569,8 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
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,
+ FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
+ DestType,
true,
FoundOverload);
if (!Fn) {
@@ -1531,7 +1597,7 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
- Sema::CheckedConversionKind CCK,
+ Sema::CheckedConversionKind CCK,
SourceRange OpRange, unsigned &msg,
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
@@ -1559,26 +1625,26 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
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.
+ // 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
+ bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
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;
}
@@ -1663,29 +1729,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
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)
+ // C++ [expr.const.cast]p3:
+ // "For two similar types T1 and T2, [...]"
+ //
+ // We only allow a const_cast to change cvr-qualifiers, not other kinds of
+ // type qualifiers. (Likewise, we ignore other changes when determining
+ // whether a cast casts away constness.)
+ if (!Self.Context.hasCvrSimilarType(SrcType, DestType))
return TC_NotApplicable;
if (NeedToMaterializeTemporary)
@@ -1913,13 +1964,19 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
return Result.isUsable();
}
+static bool IsAddressSpaceConversion(QualType SrcType, QualType DestType) {
+ return SrcType->isPointerType() && DestType->isPointerType() &&
+ SrcType->getAs<PointerType>()->getPointeeType().getAddressSpace() !=
+ DestType->getAs<PointerType>()->getPointeeType().getAddressSpace();
+}
+
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
SourceRange OpRange,
unsigned &msg,
CastKind &Kind) {
bool IsLValueCast = false;
-
+
DestType = Self.Context.getCanonicalType(DestType);
QualType SrcType = SrcExpr.get()->getType();
@@ -1962,7 +2019,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// FIXME: Use a specific diagnostic for the rest of these cases.
case OK_VectorComponent: inappropriate = "vector element"; break;
case OK_ObjCProperty: inappropriate = "property expression"; break;
- case OK_ObjCSubscript: inappropriate = "container subscripting expression";
+ case OK_ObjCSubscript: inappropriate = "container subscripting expression";
break;
}
if (inappropriate) {
@@ -1976,7 +2033,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// This code does this transformation for the checked types.
DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
SrcType = Self.Context.getPointerType(SrcType);
-
+
IsLValueCast = true;
}
@@ -1994,16 +2051,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
SrcMemPtr->isMemberFunctionPointer())
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.
@@ -2018,6 +2065,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_Failed;
}
+ // 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 (auto CACK =
+ CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+ /*CheckObjCLifetime=*/CStyle))
+ return getCastAwayConstnessCastKind(CACK, msg);
+
// A valid member pointer cast.
assert(!IsLValueCast);
Kind = CK_ReinterpretMemberPointer;
@@ -2065,18 +2121,18 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
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,
+ // 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
+ // 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;
@@ -2134,19 +2190,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
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;
+ // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
+ // The C-style cast operator can.
+ TryCastResult SuccessResult = TC_Success;
+ if (auto CACK =
+ CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+ /*CheckObjCLifetime=*/CStyle))
+ SuccessResult = getCastAwayConstnessCastKind(CACK, msg);
+
if (IsLValueCast) {
Kind = CK_LValueBitCast;
} else if (DestType->isObjCObjectPointerType()) {
@@ -2157,6 +2213,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
} else {
Kind = CK_BitCast;
}
+ } else if (IsAddressSpaceConversion(SrcType, DestType)) {
+ Kind = CK_AddressSpaceConversion;
} else {
Kind = CK_BitCast;
}
@@ -2164,7 +2222,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// Any pointer can be cast to an Objective-C pointer type with a C-style
// cast.
if (CStyle && DestType->isObjCObjectPointerType()) {
- return TC_Success;
+ return SuccessResult;
}
if (CStyle)
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
@@ -2178,7 +2236,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
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;
+ return SuccessResult;
}
// C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
@@ -2191,7 +2249,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
- return TC_Success;
+ return SuccessResult;
}
if (DestType->isFunctionPointerType()) {
@@ -2200,16 +2258,16 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
- return TC_Success;
+ return SuccessResult;
}
-
+
// 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;
-}
+ return SuccessResult;
+}
void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
bool ListInitialization) {
@@ -2238,7 +2296,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
if (claimPlaceholder(BuiltinType::Overload)) {
Self.ResolveAndFixSingleFunctionTemplateSpecialization(
- SrcExpr, /* Decay Function to ptr */ false,
+ SrcExpr, /* Decay Function to ptr */ false,
/* Complain */ true, DestRange, DestType,
diag::err_bad_cstyle_cast_overload);
if (SrcExpr.isInvalid())
@@ -2289,7 +2347,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
/*CStyle*/true, msg);
if (SrcExpr.isInvalid())
return;
- if (tcr == TC_Success)
+ if (isValidCast(tcr))
Kind = CK_NoOp;
Sema::CheckedConversionKind CCK
@@ -2312,7 +2370,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
}
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
- tcr == TC_Success)
+ isValidCast(tcr))
checkObjCConversion(CCK);
if (tcr != TC_Success && msg != 0) {
@@ -2336,16 +2394,17 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
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)
+ if (isValidCast(tcr)) {
+ if (Kind == CK_BitCast)
+ checkCastAlign();
+ } else {
SrcExpr = ExprError();
+ }
}
-/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a
+/// 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,
@@ -2353,10 +2412,10 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr,
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;
@@ -2375,7 +2434,7 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr,
return;
if (SrcType->isComplexIntegerType() && DestType->isComplexIntegerType())
return;
-
+
Self.Diag(SrcExpr.get()->getExprLoc(),
diag::warn_bad_function_cast)
<< SrcType << DestType << SrcExpr.get()->getSourceRange();
@@ -2582,26 +2641,26 @@ void CastOperation::CheckCStyleCast() {
if (const PointerType *ExprPtr = SrcType->getAs<PointerType>()) {
Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
- if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
+ if (CastPtr->getPointeeType()->isObjCLifetimeType() &&
ExprPtr->getPointeeType()->isObjCLifetimeType() &&
!CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
- Self.Diag(SrcExpr.get()->getLocStart(),
+ 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(),
+ 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);
DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange);
DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
@@ -2627,11 +2686,13 @@ static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
QualType TheOffendingSrcType, TheOffendingDestType;
Qualifiers CastAwayQualifiers;
- if (!CastsAwayConstness(Self, SrcType, DestType, true, false,
- &TheOffendingSrcType, &TheOffendingDestType,
- &CastAwayQualifiers))
+ if (CastsAwayConstness(Self, SrcType, DestType, true, false,
+ &TheOffendingSrcType, &TheOffendingDestType,
+ &CastAwayQualifiers) !=
+ CastAwayConstnessKind::CACK_Similar)
return;
+ // FIXME: 'restrict' is not properly handled here.
int qualifiers = -1;
if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
qualifiers = 0;
@@ -2653,7 +2714,7 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
TypeSourceInfo *CastTypeInfo,
SourceLocation RPLoc,
Expr *CastExpr) {
- CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
+ CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd());