aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaCast.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaCast.cpp')
-rw-r--r--clang/lib/Sema/SemaCast.cpp196
1 files changed, 162 insertions, 34 deletions
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index a905ebc67305..2efe26052c78 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -48,7 +48,8 @@ enum CastType {
CT_Reinterpret, ///< reinterpret_cast
CT_Dynamic, ///< dynamic_cast
CT_CStyle, ///< (Type)expr
- CT_Functional ///< Type(expr)
+ CT_Functional, ///< Type(expr)
+ CT_Addrspace ///< addrspace_cast
};
namespace {
@@ -88,6 +89,7 @@ namespace {
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
void CheckBuiltinBitCast();
+ void CheckAddrspaceCast();
void updatePartOfExplicitCastFlags(CastExpr *CE) {
// Walk down from the CE to the OrigSrcExpr, and mark all immediate
@@ -159,6 +161,30 @@ namespace {
PlaceholderKind = (BuiltinType::Kind) 0;
}
};
+
+ void CheckNoDeref(Sema &S, const QualType FromType, const QualType ToType,
+ SourceLocation OpLoc) {
+ if (const auto *PtrType = dyn_cast<PointerType>(FromType)) {
+ if (PtrType->getPointeeType()->hasAttr(attr::NoDeref)) {
+ if (const auto *DestType = dyn_cast<PointerType>(ToType)) {
+ if (!DestType->getPointeeType()->hasAttr(attr::NoDeref)) {
+ S.Diag(OpLoc, diag::warn_noderef_to_dereferenceable_pointer);
+ }
+ }
+ }
+ }
+ }
+
+ struct CheckNoDerefRAII {
+ CheckNoDerefRAII(CastOperation &Op) : Op(Op) {}
+ ~CheckNoDerefRAII() {
+ if (!Op.SrcExpr.isInvalid())
+ CheckNoDeref(Op.Self, Op.SrcExpr.get()->getType(), Op.ResultType,
+ Op.OpRange.getBegin());
+ }
+
+ CastOperation &Op;
+ };
}
static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
@@ -225,12 +251,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
- SourceRange OpRange,
- unsigned &msg,
+ SourceRange OpRange, unsigned &msg,
CastKind &Kind);
+static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
+ QualType DestType, bool CStyle,
+ unsigned &msg, CastKind &Kind);
-
-/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
+/// ActOnCXXNamedCast - Parse
+/// {dynamic,static,reinterpret,const,addrspace}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
SourceLocation LAngleBracketLoc, Declarator &D,
@@ -272,6 +300,16 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
switch (Kind) {
default: llvm_unreachable("Unknown C++ cast!");
+ case tok::kw_addrspace_cast:
+ if (!TypeDependent) {
+ Op.CheckAddrspaceCast();
+ if (Op.SrcExpr.isInvalid())
+ return ExprError();
+ }
+ return Op.complete(CXXAddrspaceCastExpr::Create(
+ Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
+ DestTInfo, OpLoc, Parens.getEnd(), AngleBrackets));
+
case tok::kw_const_cast:
if (!TypeDependent) {
Op.CheckConstCast();
@@ -375,6 +413,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case CT_Const:
case CT_Reinterpret:
case CT_Dynamic:
+ case CT_Addrspace:
return false;
// These do.
@@ -708,6 +747,8 @@ static TryCastResult getCastAwayConstnessCastKind(CastAwayConstnessKind CACK,
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
void CastOperation::CheckDynamicCast() {
+ CheckNoDerefRAII NoderefCheck(*this);
+
if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
@@ -861,6 +902,8 @@ void CastOperation::CheckDynamicCast() {
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
void CastOperation::CheckConstCast() {
+ CheckNoDerefRAII NoderefCheck(*this);
+
if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
@@ -878,6 +921,18 @@ void CastOperation::CheckConstCast() {
SrcExpr = ExprError();
}
+void CastOperation::CheckAddrspaceCast() {
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ auto TCR =
+ TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg, Kind);
+ if (TCR != TC_Success && msg != 0) {
+ Self.Diag(OpRange.getBegin(), msg)
+ << CT_Addrspace << SrcExpr.get()->getType() << DestType << OpRange;
+ }
+ if (!isValidCast(TCR))
+ 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,
@@ -1018,6 +1073,8 @@ void CastOperation::CheckReinterpretCast() {
/// 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() {
+ CheckNoDerefRAII NoderefCheck(*this);
+
if (isPlaceholder()) {
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid())
@@ -1961,7 +2018,7 @@ static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr,
<< FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText);
}
-static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
+static void checkIntToPointerCast(bool CStyle, const SourceRange &OpRange,
const Expr *SrcExpr, QualType DestType,
Sema &Self) {
QualType SrcType = SrcExpr->getType();
@@ -1983,7 +2040,7 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
unsigned Diag = DestType->isVoidPointerType() ?
diag::warn_int_to_void_pointer_cast
: diag::warn_int_to_pointer_cast;
- Self.Diag(Loc, Diag) << SrcType << DestType;
+ Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange;
}
}
@@ -2062,6 +2119,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
// FIXME: Use a specific diagnostic for the rest of these cases.
case OK_VectorComponent: inappropriate = "vector element"; break;
+ case OK_MatrixComponent:
+ inappropriate = "matrix element";
+ break;
case OK_ObjCProperty: inappropriate = "property expression"; break;
case OK_ObjCSubscript: inappropriate = "container subscripting expression";
break;
@@ -2204,13 +2264,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// 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;
+ Self.Context.getTypeSize(DestType))) {
+ bool MicrosoftException =
+ Self.getLangOpts().MicrosoftExt && !DestType->isBooleanType();
+ if (MicrosoftException) {
+ unsigned Diag = SrcType->isVoidPointerType()
+ ? diag::warn_void_pointer_to_int_cast
+ : diag::warn_pointer_to_int_cast;
+ Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange;
+ } else {
+ msg = diag::err_bad_reinterpret_cast_small_int;
+ return TC_Failed;
+ }
}
Kind = CK_PointerToIntegral;
return TC_Success;
@@ -2218,8 +2284,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (SrcType->isIntegralOrEnumerationType()) {
assert(destIsPtr && "One type must be a pointer");
- checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType,
- Self);
+ checkIntToPointerCast(CStyle, OpRange, 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
@@ -2311,6 +2376,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return SuccessResult;
}
+ // Diagnose address space conversion in nested pointers.
+ QualType DestPtee = DestType->getPointeeType().isNull()
+ ? DestType->getPointeeType()
+ : DestType->getPointeeType()->getPointeeType();
+ QualType SrcPtee = SrcType->getPointeeType().isNull()
+ ? SrcType->getPointeeType()
+ : SrcType->getPointeeType()->getPointeeType();
+ while (!DestPtee.isNull() && !SrcPtee.isNull()) {
+ if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) {
+ Self.Diag(OpRange.getBegin(),
+ diag::warn_bad_cxx_cast_nested_pointer_addr_space)
+ << CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange();
+ break;
+ }
+ DestPtee = DestPtee->getPointeeType();
+ SrcPtee = SrcPtee->getPointeeType();
+ }
+
// 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.
@@ -2321,7 +2404,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
- unsigned &msg) {
+ unsigned &msg, CastKind &Kind) {
if (!Self.getLangOpts().OpenCL)
// FIXME: As compiler doesn't have any information about overlapping addr
// spaces at the moment we have to be permissive here.
@@ -2330,6 +2413,9 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
// non-OpenCL mode too, we fast-path above because no other languages
// define overlapping address spaces currently.
auto SrcType = SrcExpr.get()->getType();
+ // FIXME: Should this be generalized to references? The reference parameter
+ // however becomes a reference pointee type here and therefore rejected.
+ // Perhaps this is the right behavior though according to C++.
auto SrcPtrType = SrcType->getAs<PointerType>();
if (!SrcPtrType)
return TC_NotApplicable;
@@ -2338,9 +2424,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
auto SrcPointeeType = SrcPtrType->getPointeeType();
auto DestPointeeType = DestPtrType->getPointeeType();
- if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace())
- return TC_NotApplicable;
- if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
+ if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) {
msg = diag::err_bad_cxx_cast_addr_space_mismatch;
return TC_Failed;
}
@@ -2348,10 +2432,15 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType());
auto DestPointeeTypeWithoutAS =
Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType());
- return Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
- DestPointeeTypeWithoutAS)
- ? TC_Success
- : TC_NotApplicable;
+ if (Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
+ DestPointeeTypeWithoutAS)) {
+ Kind = SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()
+ ? CK_NoOp
+ : CK_AddressSpaceConversion;
+ return TC_Success;
+ } else {
+ return TC_NotApplicable;
+ }
}
void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
@@ -2378,9 +2467,9 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
const PointerType *SrcPPtr = cast<PointerType>(SrcPtr);
QualType DestPPointee = DestPPtr->getPointeeType();
QualType SrcPPointee = SrcPPtr->getPointeeType();
- if (Nested ? DestPPointee.getAddressSpace() !=
- SrcPPointee.getAddressSpace()
- : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) {
+ if (Nested
+ ? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace()
+ : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) {
Self.Diag(OpRange.getBegin(), DiagID)
<< SrcType << DestType << Sema::AA_Casting
<< SrcExpr.get()->getSourceRange();
@@ -2482,22 +2571,21 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
Sema::CheckedConversionKind CCK =
FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
- tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg);
+ tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg,
+ Kind);
if (SrcExpr.isInvalid())
return;
- if (isValidCast(tcr))
- Kind = CK_AddressSpaceConversion;
-
if (tcr == TC_NotApplicable) {
- // ... or if that is not possible, a static_cast, ignoring const, ...
+ // ... or if that is not possible, a static_cast, ignoring const and
+ // addr space, ...
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.
+ // ... and finally a reinterpret_cast, ignoring const and addr space.
tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true,
OpRange, msg, Kind);
if (SrcExpr.isInvalid())
@@ -2629,6 +2717,13 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // Allow casting a sizeless built-in type to itself.
+ if (DestType->isSizelessBuiltinType() &&
+ Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+ Kind = CK_NoOp;
+ return;
+ }
+
if (!DestType->isScalarType() && !DestType->isVectorType()) {
const RecordType *DestRecordTy = DestType->getAs<RecordType>();
@@ -2724,6 +2819,20 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // Can't cast to or from bfloat
+ if (DestType->isBFloat16Type() && !SrcType->isBFloat16Type()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_to_bfloat16)
+ << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ if (SrcType->isBFloat16Type() && !DestType->isBFloat16Type()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_from_bfloat16)
+ << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
if (!DestType->isArithmeticType()) {
@@ -2734,8 +2843,8 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
- checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
- DestType, Self);
+ checkIntToPointerCast(/* CStyle */ true, OpRange, SrcExpr.get(), DestType,
+ Self);
} else if (!SrcType->isArithmeticType()) {
if (!DestType->isIntegralType(Self.Context) &&
DestType->isArithmeticType()) {
@@ -2745,6 +2854,25 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
+
+ if ((Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) &&
+ !DestType->isBooleanType()) {
+ // C 6.3.2.3p6: Any pointer type may be converted to an integer type.
+ // Except as previously specified, the result is implementation-defined.
+ // If the result cannot be represented in the integer type, the behavior
+ // is undefined. The result need not be in the range of values of any
+ // integer type.
+ unsigned Diag;
+ if (SrcType->isVoidPointerType())
+ Diag = DestType->isEnumeralType() ? diag::warn_void_pointer_to_enum_cast
+ : diag::warn_void_pointer_to_int_cast;
+ else if (DestType->isEnumeralType())
+ Diag = diag::warn_pointer_to_enum_cast;
+ else
+ Diag = diag::warn_pointer_to_int_cast;
+ Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange;
+ }
}
if (Self.getLangOpts().OpenCL &&