diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
commit | 2298981669bf3bd63335a4be179bc0f96823a8f4 (patch) | |
tree | 1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/Sema/SemaCast.cpp | |
parent | 9a83721404652cea39e9f02ae3e3b5c964602a5c (diff) |
Vendor import of stripped clang trunk r366426 (just before thevendor/clang/clang-trunk-r366426
release_90 branch point):
https://llvm.org/svn/llvm-project/cfe/trunk@366426
Notes
Notes:
svn path=/vendor/clang/dist/; revision=351280
svn path=/vendor/clang/clang-trunk-r366426/; revision=351281; tag=vendor/clang/clang-trunk-r366426
Diffstat (limited to 'lib/Sema/SemaCast.cpp')
-rw-r--r-- | lib/Sema/SemaCast.cpp | 219 |
1 files changed, 179 insertions, 40 deletions
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 0b4645e11c34..f184eda2f273 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1,9 +1,8 @@ //===--- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -88,6 +87,7 @@ namespace { void CheckDynamicCast(); void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); void CheckCStyleCast(); + void CheckBuiltinBitCast(); void updatePartOfExplicitCastFlags(CastExpr *CE) { // Walk down from the CE to the OrigSrcExpr, and mark all immediate @@ -285,7 +285,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, AngleBrackets)); case tok::kw_dynamic_cast: { - // OpenCL C++ 1.0 s2.9: dynamic_cast is not supported. + // dynamic_cast is not supported in C++ for OpenCL. if (getLangOpts().OpenCLCPlusPlus) { return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported) << "dynamic_cast"); @@ -332,6 +332,38 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, } } +ExprResult Sema::ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &D, + ExprResult Operand, + SourceLocation RParenLoc) { + assert(!D.isInvalidType()); + + TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, Operand.get()->getType()); + if (D.isInvalidType()) + return ExprError(); + + return BuildBuiltinBitCastExpr(KWLoc, TInfo, Operand.get(), RParenLoc); +} + +ExprResult Sema::BuildBuiltinBitCastExpr(SourceLocation KWLoc, + TypeSourceInfo *TSI, Expr *Operand, + SourceLocation RParenLoc) { + CastOperation Op(*this, TSI->getType(), Operand); + Op.OpRange = SourceRange(KWLoc, RParenLoc); + TypeLoc TL = TSI->getTypeLoc(); + Op.DestRange = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); + + if (!Operand->isTypeDependent() && !TSI->getType()->isDependentType()) { + Op.CheckBuiltinBitCast(); + if (Op.SrcExpr.isInvalid()) + return ExprError(); + } + + BuiltinBitCastExpr *BCE = + new (Context) BuiltinBitCastExpr(Op.ResultType, Op.ValueKind, Op.Kind, + Op.SrcExpr.get(), TSI, KWLoc, RParenLoc); + return Op.complete(BCE); +} + /// Try to diagnose a failed overloaded cast. Returns true if /// diagnostics were emitted. static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, @@ -400,11 +432,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, break; } - S.Diag(range.getBegin(), msg) - << CT << srcType << destType - << range << src->getSourceRange(); - - candidates.NoteCandidates(S, howManyCandidates, src); + candidates.NoteCandidates( + PartialDiagnosticAt(range.getBegin(), + S.PDiag(msg) << CT << srcType << destType << range + << src->getSourceRange()), + S, howManyCandidates, src); return true; } @@ -2012,7 +2044,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (!CStyle) { Self.CheckCompatibleReinterpretCast(SrcType, DestType, - /*isDereference=*/false, OpRange); + /*IsDereference=*/false, OpRange); } // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the @@ -2213,7 +2245,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, /*CheckObjCLifetime=*/CStyle)) SuccessResult = getCastAwayConstnessCastKind(CACK, msg); - if (IsLValueCast) { + if (IsAddressSpaceConversion(SrcType, DestType)) { + Kind = CK_AddressSpaceConversion; + assert(SrcType->isPointerType() && DestType->isPointerType()); + if (!CStyle && + !DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf( + SrcType->getPointeeType().getQualifiers())) { + SuccessResult = TC_Failed; + } + } else if (IsLValueCast) { Kind = CK_LValueBitCast; } else if (DestType->isObjCObjectPointerType()) { Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr); @@ -2223,8 +2263,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } else { Kind = CK_BitCast; } - } else if (IsAddressSpaceConversion(SrcType, DestType)) { - Kind = CK_AddressSpaceConversion; } else { Kind = CK_BitCast; } @@ -2279,23 +2317,80 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return SuccessResult; } +static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, + QualType DestType, bool CStyle, + unsigned &msg) { + 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. + return TC_NotApplicable; + // Even though the logic below is general enough and can be applied to + // non-OpenCL mode too, we fast-path above because no other languages + // define overlapping address spaces currently. + auto SrcType = SrcExpr.get()->getType(); + auto SrcPtrType = SrcType->getAs<PointerType>(); + if (!SrcPtrType) + return TC_NotApplicable; + auto DestPtrType = DestType->getAs<PointerType>(); + if (!DestPtrType) + return TC_NotApplicable; + auto SrcPointeeType = SrcPtrType->getPointeeType(); + auto DestPointeeType = DestPtrType->getPointeeType(); + if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()) + return TC_NotApplicable; + if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { + msg = diag::err_bad_cxx_cast_addr_space_mismatch; + return TC_Failed; + } + auto SrcPointeeTypeWithoutAS = + Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType()); + auto DestPointeeTypeWithoutAS = + Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType()); + return Self.Context.hasSameType(SrcPointeeTypeWithoutAS, + DestPointeeTypeWithoutAS) + ? TC_Success + : TC_NotApplicable; +} + void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { // In OpenCL only conversions between pointers to objects in overlapping // addr spaces are allowed. v2.0 s6.5.5 - Generic addr space overlaps // with any named one, except for constant. + + // Converting the top level pointee addrspace is permitted for compatible + // addrspaces (such as 'generic int *' to 'local int *' or vice versa), but + // if any of the nested pointee addrspaces differ, we emit a warning + // regardless of addrspace compatibility. This makes + // local int ** p; + // return (generic int **) p; + // warn even though local -> generic is permitted. if (Self.getLangOpts().OpenCL) { - auto SrcPtrType = SrcType->getAs<PointerType>(); - if (!SrcPtrType) - return; - auto DestPtrType = DestType->getAs<PointerType>(); - if (!DestPtrType) - return; - if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { - Self.Diag(OpRange.getBegin(), - diag::err_typecheck_incompatible_address_space) - << SrcType << DestType << Sema::AA_Casting - << SrcExpr.get()->getSourceRange(); - SrcExpr = ExprError(); + const Type *DestPtr, *SrcPtr; + bool Nested = false; + unsigned DiagID = diag::err_typecheck_incompatible_address_space; + DestPtr = Self.getASTContext().getCanonicalType(DestType.getTypePtr()), + SrcPtr = Self.getASTContext().getCanonicalType(SrcType.getTypePtr()); + + while (isa<PointerType>(DestPtr) && isa<PointerType>(SrcPtr)) { + const PointerType *DestPPtr = cast<PointerType>(DestPtr); + const PointerType *SrcPPtr = cast<PointerType>(SrcPtr); + QualType DestPPointee = DestPPtr->getPointeeType(); + QualType SrcPPointee = SrcPPtr->getPointeeType(); + if (Nested ? DestPPointee.getAddressSpace() != + SrcPPointee.getAddressSpace() + : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) { + Self.Diag(OpRange.getBegin(), DiagID) + << SrcType << DestType << Sema::AA_Casting + << SrcExpr.get()->getSourceRange(); + if (!Nested) + SrcExpr = ExprError(); + return; + } + + DestPtr = DestPPtr->getPointeeType().getTypePtr(); + SrcPtr = SrcPPtr->getPointeeType().getTypePtr(); + Nested = true; + DiagID = diag::ext_nested_pointer_qualifier_mismatch; } } } @@ -2373,30 +2468,39 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, // 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 ... + // Note that for address space we check compatibility after const_cast. unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(Self, SrcExpr, DestType, - /*CStyle*/true, msg); + /*CStyle*/ true, msg); if (SrcExpr.isInvalid()) return; if (isValidCast(tcr)) Kind = CK_NoOp; - Sema::CheckedConversionKind CCK - = FunctionalStyle? Sema::CCK_FunctionalCast - : Sema::CCK_CStyleCast; + 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); + tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg); if (SrcExpr.isInvalid()) return; + if (isValidCast(tcr)) + Kind = CK_AddressSpaceConversion; + if (tcr == TC_NotApplicable) { - // ... and finally a reinterpret_cast, ignoring const. - tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true, - OpRange, msg, Kind); + // ... 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; + } } } @@ -2427,8 +2531,6 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } } - checkAddressSpaceCast(SrcExpr.get()->getType(), DestType); - if (isValidCast(tcr)) { if (Kind == CK_BitCast) checkCastAlign(); @@ -2695,6 +2797,43 @@ void CastOperation::CheckCStyleCast() { checkCastAlign(); } +void CastOperation::CheckBuiltinBitCast() { + QualType SrcType = SrcExpr.get()->getType(); + if (SrcExpr.get()->isRValue()) + SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(), + /*IsLValueReference=*/false); + + CharUnits DestSize = Self.Context.getTypeSizeInChars(DestType); + CharUnits SourceSize = Self.Context.getTypeSizeInChars(SrcType); + if (DestSize != SourceSize) { + Self.Diag(OpRange.getBegin(), diag::err_bit_cast_type_size_mismatch) + << (int)SourceSize.getQuantity() << (int)DestSize.getQuantity(); + SrcExpr = ExprError(); + return; + } + + if (!DestType.isTriviallyCopyableType(Self.Context)) { + Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable) + << 1; + SrcExpr = ExprError(); + return; + } + + if (!SrcType.isTriviallyCopyableType(Self.Context)) { + Self.Diag(OpRange.getBegin(), diag::err_bit_cast_non_trivially_copyable) + << 0; + SrcExpr = ExprError(); + return; + } + + if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) { + Kind = CK_NoOp; + return; + } + + Kind = CK_LValueToRValueBitCast; +} + /// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either /// const, volatile or both. static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, @@ -2742,7 +2881,7 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, Op.OpRange = SourceRange(LPLoc, CastExpr->getEndLoc()); if (getLangOpts().CPlusPlus) { - Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false, + Op.CheckCXXCStyleCast(/*FunctionalCast=*/ false, isa<InitListExpr>(CastExpr)); } else { Op.CheckCStyleCast(); @@ -2769,7 +2908,7 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getEndLoc()); - Op.CheckCXXCStyleCast(/*FunctionalStyle=*/true, /*ListInit=*/false); + Op.CheckCXXCStyleCast(/*FunctionalCast=*/true, /*ListInit=*/false); if (Op.SrcExpr.isInvalid()) return ExprError(); |