diff options
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 540 |
1 files changed, 424 insertions, 116 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 8dc1fdb769..d0479b832f 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1,9 +1,8 @@ //===- SemaChecking.cpp - Extra Semantic Checking -------------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -236,47 +235,6 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { return false; } -static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, - CallExpr *TheCall, unsigned SizeIdx, - unsigned DstSizeIdx, - StringRef LikelyMacroName) { - if (TheCall->getNumArgs() <= SizeIdx || - TheCall->getNumArgs() <= DstSizeIdx) - return; - - const Expr *SizeArg = TheCall->getArg(SizeIdx); - const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx); - - Expr::EvalResult SizeResult, DstSizeResult; - - // find out if both sizes are known at compile time - if (!SizeArg->EvaluateAsInt(SizeResult, S.Context) || - !DstSizeArg->EvaluateAsInt(DstSizeResult, S.Context)) - return; - - llvm::APSInt Size = SizeResult.Val.getInt(); - llvm::APSInt DstSize = DstSizeResult.Val.getInt(); - - if (Size.ule(DstSize)) - return; - - // Confirmed overflow, so generate the diagnostic. - StringRef FunctionName = FDecl->getName(); - SourceLocation SL = TheCall->getBeginLoc(); - SourceManager &SM = S.getSourceManager(); - // If we're in an expansion of a macro whose name corresponds to this builtin, - // use the simple macro name and location. - if (SL.isMacroID() && Lexer::getImmediateMacroName(SL, SM, S.getLangOpts()) == - LikelyMacroName) { - FunctionName = LikelyMacroName; - SL = SM.getImmediateMacroCallerLoc(SL); - } - - S.Diag(SL, diag::warn_memcpy_chk_overflow) - << FunctionName << DstSize.toString(/*Radix=*/10) - << Size.toString(/*Radix=*/10); -} - static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { if (checkArgCount(S, BuiltinCall, 2)) return true; @@ -340,6 +298,148 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { return false; } +/// Check a call to BuiltinID for buffer overflows. If BuiltinID is a +/// __builtin_*_chk function, then use the object size argument specified in the +/// source. Otherwise, infer the object size using __builtin_object_size. +void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, + CallExpr *TheCall) { + // FIXME: There are some more useful checks we could be doing here: + // - Analyze the format string of sprintf to see how much of buffer is used. + // - Evaluate strlen of strcpy arguments, use as object size. + + if (TheCall->isValueDependent() || TheCall->isTypeDependent()) + return; + + unsigned BuiltinID = FD->getBuiltinID(/*ConsiderWrappers=*/true); + if (!BuiltinID) + return; + + unsigned DiagID = 0; + bool IsChkVariant = false; + unsigned SizeIndex, ObjectIndex; + switch (BuiltinID) { + default: + return; + case Builtin::BI__builtin___memcpy_chk: + case Builtin::BI__builtin___memmove_chk: + case Builtin::BI__builtin___memset_chk: + case Builtin::BI__builtin___strlcat_chk: + case Builtin::BI__builtin___strlcpy_chk: + case Builtin::BI__builtin___strncat_chk: + case Builtin::BI__builtin___strncpy_chk: + case Builtin::BI__builtin___stpncpy_chk: + case Builtin::BI__builtin___memccpy_chk: { + DiagID = diag::warn_builtin_chk_overflow; + IsChkVariant = true; + SizeIndex = TheCall->getNumArgs() - 2; + ObjectIndex = TheCall->getNumArgs() - 1; + break; + } + + case Builtin::BI__builtin___snprintf_chk: + case Builtin::BI__builtin___vsnprintf_chk: { + DiagID = diag::warn_builtin_chk_overflow; + IsChkVariant = true; + SizeIndex = 1; + ObjectIndex = 3; + break; + } + + case Builtin::BIstrncat: + case Builtin::BI__builtin_strncat: + case Builtin::BIstrncpy: + case Builtin::BI__builtin_strncpy: + case Builtin::BIstpncpy: + case Builtin::BI__builtin_stpncpy: { + // Whether these functions overflow depends on the runtime strlen of the + // string, not just the buffer size, so emitting the "always overflow" + // diagnostic isn't quite right. We should still diagnose passing a buffer + // size larger than the destination buffer though; this is a runtime abort + // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise. + DiagID = diag::warn_fortify_source_size_mismatch; + SizeIndex = TheCall->getNumArgs() - 1; + ObjectIndex = 0; + break; + } + + case Builtin::BImemcpy: + case Builtin::BI__builtin_memcpy: + case Builtin::BImemmove: + case Builtin::BI__builtin_memmove: + case Builtin::BImemset: + case Builtin::BI__builtin_memset: { + DiagID = diag::warn_fortify_source_overflow; + SizeIndex = TheCall->getNumArgs() - 1; + ObjectIndex = 0; + break; + } + case Builtin::BIsnprintf: + case Builtin::BI__builtin_snprintf: + case Builtin::BIvsnprintf: + case Builtin::BI__builtin_vsnprintf: { + DiagID = diag::warn_fortify_source_size_mismatch; + SizeIndex = 1; + ObjectIndex = 0; + break; + } + } + + llvm::APSInt ObjectSize; + // For __builtin___*_chk, the object size is explicitly provided by the caller + // (usually using __builtin_object_size). Use that value to check this call. + if (IsChkVariant) { + Expr::EvalResult Result; + Expr *SizeArg = TheCall->getArg(ObjectIndex); + if (!SizeArg->EvaluateAsInt(Result, getASTContext())) + return; + ObjectSize = Result.Val.getInt(); + + // Otherwise, try to evaluate an imaginary call to __builtin_object_size. + } else { + // If the parameter has a pass_object_size attribute, then we should use its + // (potentially) more strict checking mode. Otherwise, conservatively assume + // type 0. + int BOSType = 0; + if (const auto *POS = + FD->getParamDecl(ObjectIndex)->getAttr<PassObjectSizeAttr>()) + BOSType = POS->getType(); + + Expr *ObjArg = TheCall->getArg(ObjectIndex); + uint64_t Result; + if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) + return; + // Get the object size in the target's size_t width. + const TargetInfo &TI = getASTContext().getTargetInfo(); + unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); + ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); + } + + // Evaluate the number of bytes of the object that this call will use. + Expr::EvalResult Result; + Expr *UsedSizeArg = TheCall->getArg(SizeIndex); + if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext())) + return; + llvm::APSInt UsedSize = Result.Val.getInt(); + + if (UsedSize.ule(ObjectSize)) + return; + + StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID); + // Skim off the details of whichever builtin was called to produce a better + // diagnostic, as it's unlikley that the user wrote the __builtin explicitly. + if (IsChkVariant) { + FunctionName = FunctionName.drop_front(std::strlen("__builtin___")); + FunctionName = FunctionName.drop_back(std::strlen("_chk")); + } else if (FunctionName.startswith("__builtin_")) { + FunctionName = FunctionName.drop_front(std::strlen("__builtin_")); + } + + DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, + PDiag(DiagID) + << FunctionName << ObjectSize.toString(/*Radix=*/10) + << UsedSize.toString(/*Radix=*/10)); +} + static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, Scope::ScopeFlags NeededScopeFlags, unsigned DiagID) { @@ -1077,6 +1177,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinAssumeAligned(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); @@ -1098,10 +1199,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (checkArgCount(*this, TheCall, 1)) return true; TheCall->setType(Context.IntTy); break; - case Builtin::BI__builtin_constant_p: + case Builtin::BI__builtin_constant_p: { if (checkArgCount(*this, TheCall, 1)) return true; + ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); + if (Arg.isInvalid()) return true; + TheCall->setArg(0, Arg.get()); TheCall->setType(Context.IntTy); break; + } case Builtin::BI__builtin_launder: return SemaBuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: @@ -1302,42 +1407,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } - - // check secure string manipulation functions where overflows - // are detectable at compile time - case Builtin::BI__builtin___memcpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memcpy"); - break; - case Builtin::BI__builtin___memmove_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memmove"); - break; - case Builtin::BI__builtin___memset_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "memset"); - break; - case Builtin::BI__builtin___strlcat_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strlcat"); - break; - case Builtin::BI__builtin___strlcpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strlcpy"); - break; - case Builtin::BI__builtin___strncat_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strncat"); - break; - case Builtin::BI__builtin___strncpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "strncpy"); - break; - case Builtin::BI__builtin___stpncpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3, "stpncpy"); - break; - case Builtin::BI__builtin___memccpy_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 3, 4, "memccpy"); - break; - case Builtin::BI__builtin___snprintf_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3, "snprintf"); - break; - case Builtin::BI__builtin___vsnprintf_chk: - SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3, "vsnprintf"); - break; case Builtin::BI__builtin_call_with_static_chain: if (SemaBuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); @@ -1806,6 +1875,16 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, BuiltinID == AArch64::BI__builtin_arm_wsr64) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + // Memory Tagging Extensions (MTE) Intrinsics + if (BuiltinID == AArch64::BI__builtin_arm_irg || + BuiltinID == AArch64::BI__builtin_arm_addg || + BuiltinID == AArch64::BI__builtin_arm_gmi || + BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg || + BuiltinID == AArch64::BI__builtin_arm_subp) { + return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall); + } + if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || @@ -3364,9 +3443,13 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtdq2ps512_mask: case X86::BI__builtin_ia32_cvtudq2ps512_mask: case X86::BI__builtin_ia32_cvtpd2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2dq512_mask: case X86::BI__builtin_ia32_cvtpd2qq512_mask: + case X86::BI__builtin_ia32_cvtpd2udq512_mask: case X86::BI__builtin_ia32_cvtpd2uqq512_mask: + case X86::BI__builtin_ia32_cvtps2dq512_mask: case X86::BI__builtin_ia32_cvtps2qq512_mask: + case X86::BI__builtin_ia32_cvtps2udq512_mask: case X86::BI__builtin_ia32_cvtps2uqq512_mask: case X86::BI__builtin_ia32_cvtqq2pd512_mask: case X86::BI__builtin_ia32_cvtqq2ps512_mask: @@ -6029,6 +6112,160 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions +bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID == AArch64::BI__builtin_arm_irg) { + if (checkArgCount(*this, TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + ExprResult SecArg = DefaultLvalueConversion(Arg1); + if (SecArg.isInvalid()) + return true; + QualType SecArgType = SecArg.get()->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_addg) { + if (checkArgCount(*this, TheCall, 2)) + return true; + + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + TheCall->setType(FirstArgType); + + // Second arg must be an constant in range [0,15] + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + } + + if (BuiltinID == AArch64::BI__builtin_arm_gmi) { + if (checkArgCount(*this, TheCall, 2)) + return true; + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + + QualType SecArgType = Arg1->getType(); + if (!SecArgType->isIntegerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) + << "second" << SecArgType << Arg1->getSourceRange(); + TheCall->setType(Context.IntTy); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_ldg || + BuiltinID == AArch64::BI__builtin_arm_stg) { + if (checkArgCount(*this, TheCall, 1)) + return true; + Expr *Arg0 = TheCall->getArg(0); + ExprResult FirstArg = DefaultFunctionArrayLvalueConversion(Arg0); + if (FirstArg.isInvalid()) + return true; + + QualType FirstArgType = FirstArg.get()->getType(); + if (!FirstArgType->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) + << "first" << FirstArgType << Arg0->getSourceRange(); + TheCall->setArg(0, FirstArg.get()); + + // Derive the return type from the pointer argument. + if (BuiltinID == AArch64::BI__builtin_arm_ldg) + TheCall->setType(FirstArgType); + return false; + } + + if (BuiltinID == AArch64::BI__builtin_arm_subp) { + Expr *ArgA = TheCall->getArg(0); + Expr *ArgB = TheCall->getArg(1); + + ExprResult ArgExprA = DefaultFunctionArrayLvalueConversion(ArgA); + ExprResult ArgExprB = DefaultFunctionArrayLvalueConversion(ArgB); + + if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) + return true; + + QualType ArgTypeA = ArgExprA.get()->getType(); + QualType ArgTypeB = ArgExprB.get()->getType(); + + auto isNull = [&] (Expr *E) -> bool { + return E->isNullPointerConstant( + Context, Expr::NPC_ValueDependentIsNotNull); }; + + // argument should be either a pointer or null + if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "first" << ArgTypeA << ArgA->getSourceRange(); + + if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) + << "second" << ArgTypeB << ArgB->getSourceRange(); + + // Ensure Pointee types are compatible + if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && + ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { + QualType pointeeA = ArgTypeA->getPointeeType(); + QualType pointeeB = ArgTypeB->getPointeeType(); + if (!Context.typesAreCompatible( + Context.getCanonicalType(pointeeA).getUnqualifiedType(), + Context.getCanonicalType(pointeeB).getUnqualifiedType())) { + return Diag(TheCall->getBeginLoc(), diag::err_typecheck_sub_ptr_compatible) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange() + << ArgB->getSourceRange(); + } + } + + // at least one argument should be pointer type + if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) + return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) + << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); + + if (isNull(ArgA)) // adopt type of the other pointer + ArgExprA = ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); + + if (isNull(ArgB)) + ArgExprB = ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); + + TheCall->setArg(0, ArgExprA.get()); + TheCall->setArg(1, ArgExprB.get()); + TheCall->setType(Context.LongLongTy); + return false; + } + assert(false && "Unhandled ARM MTE intrinsic"); + return true; +} + /// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, @@ -7651,7 +7888,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier startSpecifier, specifierLen); // Check the length modifier is valid with the given conversion specifier. - if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), + S.getLangOpts())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_nonsensical_length); else if (!FS.hasStandardLengthModifier()) @@ -8155,7 +8393,8 @@ bool CheckScanfHandler::HandleScanfSpecifier( } // Check the length modifier is valid with the given conversion specifier. - if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), + S.getLangOpts())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_nonsensical_length); else if (!FS.hasStandardLengthModifier()) @@ -9172,23 +9411,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, getContainedDynamicClass(PointeeTy, IsContained)) { unsigned OperationType = 0; + const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp; // "overwritten" if we're warning about the destination for any call // but memcmp; otherwise a verb appropriate to the call. - if (ArgIdx != 0 || BId == Builtin::BImemcmp) { + if (ArgIdx != 0 || IsCmp) { if (BId == Builtin::BImemcpy) OperationType = 1; else if(BId == Builtin::BImemmove) OperationType = 2; - else if (BId == Builtin::BImemcmp) + else if (IsCmp) OperationType = 3; } - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_dyn_class_memaccess) - << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx) - << FnName << IsContained << ContainedRD << OperationType - << Call->getCallee()->getSourceRange()); + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_dyn_class_memaccess) + << (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName + << IsContained << ContainedRD << OperationType + << Call->getCallee()->getSourceRange()); } else if (PointeeTy.hasNonTrivialObjCLifetime() && BId != Builtin::BImemset) DiagRuntimeBehavior( @@ -10622,16 +10861,18 @@ static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { // The below checks assume source is floating point. if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return; - // If source is floating point but target is not. + // If source is floating point but target is an integer. + if (ResultBT->isInteger()) + return DiagnoseImpCast(S, E, E->getRHS()->getType(), E->getLHS()->getType(), + E->getExprLoc(), diag::warn_impcast_float_integer); + if (!ResultBT->isFloatingPoint()) - return DiagnoseFloatingImpCast(S, E, E->getRHS()->getType(), - E->getExprLoc()); - - // If both source and target are floating points. - // Builtin FP kinds are ordered by increasing FP rank. - if (ResultBT->getKind() < RBT->getKind() && - // We don't want to warn for system macro. - !S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) + return; + + // If both source and target are floating points, warn about losing precision. + int Order = S.getASTContext().getFloatingTypeSemanticOrder( + QualType(ResultBT, 0), QualType(RBT, 0)); + if (Order < 0 && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) // warn about dropping FP rank. DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), E->getOperatorLoc(), diag::warn_impcast_float_result_precision); @@ -10950,8 +11191,9 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, if (TargetBT && TargetBT->isFloatingPoint()) { // ...then warn if we're dropping FP rank. - // Builtin FP kinds are ordered by increasing FP rank. - if (SourceBT->getKind() > TargetBT->getKind()) { + int Order = S.getASTContext().getFloatingTypeSemanticOrder( + QualType(SourceBT, 0), QualType(TargetBT, 0)); + if (Order > 0) { // Don't warn about float constants that are precisely // representable in the target type. Expr::EvalResult result; @@ -10969,7 +11211,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); } // ... or possibly if we're increasing rank, too - else if (TargetBT->getKind() > SourceBT->getKind()) { + else if (Order < 0) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -11013,6 +11255,67 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, return; } + // Valid casts involving fixed point types should be accounted for here. + if (Source->isFixedPointType()) { + if (Target->isUnsaturatedFixedPointType()) { + Expr::EvalResult Result; + if (E->EvaluateAsFixedPoint(Result, S.Context, + Expr::SE_AllowSideEffects)) { + APFixedPoint Value = Result.Val.getFixedPoint(); + APFixedPoint MaxVal = S.Context.getFixedPointMax(T); + APFixedPoint MinVal = S.Context.getFixedPointMin(T); + if (Value > MaxVal || Value < MinVal) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_fixed_point_range) + << Value.toString() << T + << E->getSourceRange() + << clang::SourceRange(CC)); + return; + } + } + } else if (Target->isIntegerType()) { + Expr::EvalResult Result; + if (E->EvaluateAsFixedPoint(Result, S.Context, + Expr::SE_AllowSideEffects)) { + APFixedPoint FXResult = Result.Val.getFixedPoint(); + + bool Overflowed; + llvm::APSInt IntResult = FXResult.convertToInt( + S.Context.getIntWidth(T), + Target->isSignedIntegerOrEnumerationType(), &Overflowed); + + if (Overflowed) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_fixed_point_range) + << FXResult.toString() << T + << E->getSourceRange() + << clang::SourceRange(CC)); + return; + } + } + } + } else if (Target->isUnsaturatedFixedPointType()) { + if (Source->isIntegerType()) { + Expr::EvalResult Result; + if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { + llvm::APSInt Value = Result.Val.getInt(); + + bool Overflowed; + APFixedPoint IntResult = APFixedPoint::getFromIntValue( + Value, S.Context.getFixedPointSemantics(T), &Overflowed); + + if (Overflowed) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_fixed_point_range) + << Value.toString(/*radix=*/10) << T + << E->getSourceRange() + << clang::SourceRange(CC)); + return; + } + } + } + } + DiagnoseNullConversion(S, E, T, CC); S.DiscardMisalignedMemberAddress(Target, E); @@ -11464,6 +11767,9 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, } if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { + // Skip function template not specialized yet. + if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return; auto ParamIter = llvm::find(FD->parameters(), PV); assert(ParamIter != FD->param_end()); unsigned ParamNo = std::distance(FD->param_begin(), ParamIter); @@ -11641,12 +11947,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { class Seq { friend class SequenceTree; - unsigned Index = 0; + unsigned Index; explicit Seq(unsigned N) : Index(N) {} public: - Seq() = default; + Seq() : Index(0) {} }; SequenceTree() { Values.push_back(Value(0)); } @@ -11710,19 +12016,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; struct Usage { - Expr *Use = nullptr; + Expr *Use; SequenceTree::Seq Seq; - Usage() = default; + Usage() : Use(nullptr), Seq() {} }; struct UsageInfo { Usage Uses[UK_Count]; /// Have we issued a diagnostic for this variable already? - bool Diagnosed = false; + bool Diagnosed; - UsageInfo() = default; + UsageInfo() : Uses(), Diagnosed(false) {} }; using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>; @@ -11849,10 +12155,11 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { if (OtherKind == UK_Use) std::swap(Mod, ModOrUse); - SemaRef.Diag(Mod->getExprLoc(), - IsModMod ? diag::warn_unsequenced_mod_mod - : diag::warn_unsequenced_mod_use) - << O << SourceRange(ModOrUse->getExprLoc()); + SemaRef.DiagRuntimeBehavior( + Mod->getExprLoc(), {Mod, ModOrUse}, + SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod + : diag::warn_unsequenced_mod_use) + << O << SourceRange(ModOrUse->getExprLoc())); UI.Diagnosed = true; } @@ -12395,6 +12702,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, return; const Type *BaseType = ArrayTy->getElementType().getTypePtr(); + if (EffectiveType->isDependentType() || BaseType->isDependentType()) + return; Expr::EvalResult Result; if (!IndexExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) @@ -13787,8 +14096,7 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); if (isa<MemberExpr>(Op)) { - auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), - MisalignedMember(Op)); + auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op)); if (MA != MisalignedMembers.end() && (T->isIntegerType() || (T->isPointerType() && (T->getPointeeType()->isIncompleteType() || |