| //===- SemaChecking.cpp - Extra Semantic Checking -------------------------===// | 
 | // | 
 | // 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 | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | //  This file implements extra semantic analysis beyond what is enforced | 
 | //  by the C type system. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "CheckExprLifetime.h" | 
 | #include "clang/AST/APValue.h" | 
 | #include "clang/AST/ASTContext.h" | 
 | #include "clang/AST/ASTDiagnostic.h" | 
 | #include "clang/AST/Attr.h" | 
 | #include "clang/AST/AttrIterator.h" | 
 | #include "clang/AST/CharUnits.h" | 
 | #include "clang/AST/Decl.h" | 
 | #include "clang/AST/DeclBase.h" | 
 | #include "clang/AST/DeclCXX.h" | 
 | #include "clang/AST/DeclObjC.h" | 
 | #include "clang/AST/DeclarationName.h" | 
 | #include "clang/AST/EvaluatedExprVisitor.h" | 
 | #include "clang/AST/Expr.h" | 
 | #include "clang/AST/ExprCXX.h" | 
 | #include "clang/AST/ExprObjC.h" | 
 | #include "clang/AST/FormatString.h" | 
 | #include "clang/AST/IgnoreExpr.h" | 
 | #include "clang/AST/NSAPI.h" | 
 | #include "clang/AST/NonTrivialTypeVisitor.h" | 
 | #include "clang/AST/OperationKinds.h" | 
 | #include "clang/AST/RecordLayout.h" | 
 | #include "clang/AST/Stmt.h" | 
 | #include "clang/AST/TemplateBase.h" | 
 | #include "clang/AST/TemplateName.h" | 
 | #include "clang/AST/Type.h" | 
 | #include "clang/AST/TypeLoc.h" | 
 | #include "clang/AST/UnresolvedSet.h" | 
 | #include "clang/Basic/AddressSpaces.h" | 
 | #include "clang/Basic/Diagnostic.h" | 
 | #include "clang/Basic/DiagnosticSema.h" | 
 | #include "clang/Basic/IdentifierTable.h" | 
 | #include "clang/Basic/LLVM.h" | 
 | #include "clang/Basic/LangOptions.h" | 
 | #include "clang/Basic/OpenCLOptions.h" | 
 | #include "clang/Basic/OperatorKinds.h" | 
 | #include "clang/Basic/PartialDiagnostic.h" | 
 | #include "clang/Basic/SourceLocation.h" | 
 | #include "clang/Basic/SourceManager.h" | 
 | #include "clang/Basic/Specifiers.h" | 
 | #include "clang/Basic/SyncScope.h" | 
 | #include "clang/Basic/TargetInfo.h" | 
 | #include "clang/Basic/TypeTraits.h" | 
 | #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering. | 
 | #include "clang/Sema/Initialization.h" | 
 | #include "clang/Sema/Lookup.h" | 
 | #include "clang/Sema/Ownership.h" | 
 | #include "clang/Sema/Scope.h" | 
 | #include "clang/Sema/ScopeInfo.h" | 
 | #include "clang/Sema/Sema.h" | 
 | #include "clang/Sema/SemaAMDGPU.h" | 
 | #include "clang/Sema/SemaARM.h" | 
 | #include "clang/Sema/SemaBPF.h" | 
 | #include "clang/Sema/SemaDirectX.h" | 
 | #include "clang/Sema/SemaHLSL.h" | 
 | #include "clang/Sema/SemaHexagon.h" | 
 | #include "clang/Sema/SemaLoongArch.h" | 
 | #include "clang/Sema/SemaMIPS.h" | 
 | #include "clang/Sema/SemaNVPTX.h" | 
 | #include "clang/Sema/SemaObjC.h" | 
 | #include "clang/Sema/SemaOpenCL.h" | 
 | #include "clang/Sema/SemaPPC.h" | 
 | #include "clang/Sema/SemaRISCV.h" | 
 | #include "clang/Sema/SemaSPIRV.h" | 
 | #include "clang/Sema/SemaSystemZ.h" | 
 | #include "clang/Sema/SemaWasm.h" | 
 | #include "clang/Sema/SemaX86.h" | 
 | #include "llvm/ADT/APFloat.h" | 
 | #include "llvm/ADT/APInt.h" | 
 | #include "llvm/ADT/APSInt.h" | 
 | #include "llvm/ADT/ArrayRef.h" | 
 | #include "llvm/ADT/DenseMap.h" | 
 | #include "llvm/ADT/FoldingSet.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/ADT/STLForwardCompat.h" | 
 | #include "llvm/ADT/SmallBitVector.h" | 
 | #include "llvm/ADT/SmallPtrSet.h" | 
 | #include "llvm/ADT/SmallString.h" | 
 | #include "llvm/ADT/SmallVector.h" | 
 | #include "llvm/ADT/StringExtras.h" | 
 | #include "llvm/ADT/StringRef.h" | 
 | #include "llvm/ADT/StringSet.h" | 
 | #include "llvm/ADT/StringSwitch.h" | 
 | #include "llvm/Support/AtomicOrdering.h" | 
 | #include "llvm/Support/Compiler.h" | 
 | #include "llvm/Support/ConvertUTF.h" | 
 | #include "llvm/Support/ErrorHandling.h" | 
 | #include "llvm/Support/Format.h" | 
 | #include "llvm/Support/Locale.h" | 
 | #include "llvm/Support/MathExtras.h" | 
 | #include "llvm/Support/SaveAndRestore.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | #include "llvm/TargetParser/RISCVTargetParser.h" | 
 | #include "llvm/TargetParser/Triple.h" | 
 | #include <algorithm> | 
 | #include <cassert> | 
 | #include <cctype> | 
 | #include <cstddef> | 
 | #include <cstdint> | 
 | #include <functional> | 
 | #include <limits> | 
 | #include <optional> | 
 | #include <string> | 
 | #include <tuple> | 
 | #include <utility> | 
 |  | 
 | using namespace clang; | 
 | using namespace sema; | 
 |  | 
 | SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, | 
 |                                                     unsigned ByteNo) const { | 
 |   return SL->getLocationOfByte(ByteNo, getSourceManager(), LangOpts, | 
 |                                Context.getTargetInfo()); | 
 | } | 
 |  | 
 | static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A, | 
 |                                             Sema::FormatArgumentPassingKind B) { | 
 |   return (A << 8) | B; | 
 | } | 
 |  | 
 | bool Sema::checkArgCountAtLeast(CallExpr *Call, unsigned MinArgCount) { | 
 |   unsigned ArgCount = Call->getNumArgs(); | 
 |   if (ArgCount >= MinArgCount) | 
 |     return false; | 
 |  | 
 |   return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args) | 
 |          << 0 /*function call*/ << MinArgCount << ArgCount | 
 |          << /*is non object*/ 0 << Call->getSourceRange(); | 
 | } | 
 |  | 
 | bool Sema::checkArgCountAtMost(CallExpr *Call, unsigned MaxArgCount) { | 
 |   unsigned ArgCount = Call->getNumArgs(); | 
 |   if (ArgCount <= MaxArgCount) | 
 |     return false; | 
 |   return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_many_args_at_most) | 
 |          << 0 /*function call*/ << MaxArgCount << ArgCount | 
 |          << /*is non object*/ 0 << Call->getSourceRange(); | 
 | } | 
 |  | 
 | bool Sema::checkArgCountRange(CallExpr *Call, unsigned MinArgCount, | 
 |                               unsigned MaxArgCount) { | 
 |   return checkArgCountAtLeast(Call, MinArgCount) || | 
 |          checkArgCountAtMost(Call, MaxArgCount); | 
 | } | 
 |  | 
 | bool Sema::checkArgCount(CallExpr *Call, unsigned DesiredArgCount) { | 
 |   unsigned ArgCount = Call->getNumArgs(); | 
 |   if (ArgCount == DesiredArgCount) | 
 |     return false; | 
 |  | 
 |   if (checkArgCountAtLeast(Call, DesiredArgCount)) | 
 |     return true; | 
 |   assert(ArgCount > DesiredArgCount && "should have diagnosed this"); | 
 |  | 
 |   // Highlight all the excess arguments. | 
 |   SourceRange Range(Call->getArg(DesiredArgCount)->getBeginLoc(), | 
 |                     Call->getArg(ArgCount - 1)->getEndLoc()); | 
 |  | 
 |   return Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args) | 
 |          << 0 /*function call*/ << DesiredArgCount << ArgCount | 
 |          << /*is non object*/ 0 << Range; | 
 | } | 
 |  | 
 | static bool checkBuiltinVerboseTrap(CallExpr *Call, Sema &S) { | 
 |   bool HasError = false; | 
 |  | 
 |   for (const Expr *Arg : Call->arguments()) { | 
 |     if (Arg->isValueDependent()) | 
 |       continue; | 
 |  | 
 |     std::optional<std::string> ArgString = Arg->tryEvaluateString(S.Context); | 
 |     int DiagMsgKind = -1; | 
 |     // Arguments must be pointers to constant strings and cannot use '$'. | 
 |     if (!ArgString.has_value()) | 
 |       DiagMsgKind = 0; | 
 |     else if (ArgString->find('$') != std::string::npos) | 
 |       DiagMsgKind = 1; | 
 |  | 
 |     if (DiagMsgKind >= 0) { | 
 |       S.Diag(Arg->getBeginLoc(), diag::err_builtin_verbose_trap_arg) | 
 |           << DiagMsgKind << Arg->getSourceRange(); | 
 |       HasError = true; | 
 |     } | 
 |   } | 
 |  | 
 |   return !HasError; | 
 | } | 
 |  | 
 | static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) { | 
 |   if (Value->isTypeDependent()) | 
 |     return false; | 
 |  | 
 |   InitializedEntity Entity = | 
 |       InitializedEntity::InitializeParameter(S.Context, Ty, false); | 
 |   ExprResult Result = | 
 |       S.PerformCopyInitialization(Entity, SourceLocation(), Value); | 
 |   if (Result.isInvalid()) | 
 |     return true; | 
 |   Value = Result.get(); | 
 |   return false; | 
 | } | 
 |  | 
 | /// Check that the first argument to __builtin_annotation is an integer | 
 | /// and the second argument is a non-wide string literal. | 
 | static bool BuiltinAnnotation(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 2)) | 
 |     return true; | 
 |  | 
 |   // First argument should be an integer. | 
 |   Expr *ValArg = TheCall->getArg(0); | 
 |   QualType Ty = ValArg->getType(); | 
 |   if (!Ty->isIntegerType()) { | 
 |     S.Diag(ValArg->getBeginLoc(), diag::err_builtin_annotation_first_arg) | 
 |         << ValArg->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Second argument should be a constant string. | 
 |   Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts(); | 
 |   StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg); | 
 |   if (!Literal || !Literal->isOrdinary()) { | 
 |     S.Diag(StrArg->getBeginLoc(), diag::err_builtin_annotation_second_arg) | 
 |         << StrArg->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   TheCall->setType(Ty); | 
 |   return false; | 
 | } | 
 |  | 
 | static bool BuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { | 
 |   // We need at least one argument. | 
 |   if (TheCall->getNumArgs() < 1) { | 
 |     S.Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) | 
 |         << 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0 | 
 |         << TheCall->getCallee()->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // All arguments should be wide string literals. | 
 |   for (Expr *Arg : TheCall->arguments()) { | 
 |     auto *Literal = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts()); | 
 |     if (!Literal || !Literal->isWide()) { | 
 |       S.Diag(Arg->getBeginLoc(), diag::err_msvc_annotation_wide_str) | 
 |           << Arg->getSourceRange(); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | /// Check that the argument to __builtin_addressof is a glvalue, and set the | 
 | /// result type to the corresponding pointer type. | 
 | static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   ExprResult Arg(TheCall->getArg(0)); | 
 |   QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getBeginLoc()); | 
 |   if (ResultType.isNull()) | 
 |     return true; | 
 |  | 
 |   TheCall->setArg(0, Arg.get()); | 
 |   TheCall->setType(ResultType); | 
 |   return false; | 
 | } | 
 |  | 
 | /// Check that the argument to __builtin_function_start is a function. | 
 | static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   if (TheCall->getArg(0)->containsErrors()) | 
 |     return true; | 
 |  | 
 |   ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); | 
 |   if (Arg.isInvalid()) | 
 |     return true; | 
 |  | 
 |   TheCall->setArg(0, Arg.get()); | 
 |   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>( | 
 |       Arg.get()->getAsBuiltinConstantDeclRef(S.getASTContext())); | 
 |  | 
 |   if (!FD) { | 
 |     S.Diag(TheCall->getBeginLoc(), diag::err_function_start_invalid_type) | 
 |         << TheCall->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   return !S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, | 
 |                                               TheCall->getBeginLoc()); | 
 | } | 
 |  | 
 | /// Check the number of arguments and set the result type to | 
 | /// the argument type. | 
 | static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   TheCall->setType(TheCall->getArg(0)->getType()); | 
 |   return false; | 
 | } | 
 |  | 
 | /// Check that the value argument for __builtin_is_aligned(value, alignment) and | 
 | /// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer | 
 | /// type (but not a function pointer) and that the alignment is a power-of-two. | 
 | static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { | 
 |   if (S.checkArgCount(TheCall, 2)) | 
 |     return true; | 
 |  | 
 |   clang::Expr *Source = TheCall->getArg(0); | 
 |   bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned; | 
 |  | 
 |   auto IsValidIntegerType = [](QualType Ty) { | 
 |     return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType(); | 
 |   }; | 
 |   QualType SrcTy = Source->getType(); | 
 |   // We should also be able to use it with arrays (but not functions!). | 
 |   if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) { | 
 |     SrcTy = S.Context.getDecayedType(SrcTy); | 
 |   } | 
 |   if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) || | 
 |       SrcTy->isFunctionPointerType()) { | 
 |     // FIXME: this is not quite the right error message since we don't allow | 
 |     // floating point types, or member pointers. | 
 |     S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand) | 
 |         << SrcTy; | 
 |     return true; | 
 |   } | 
 |  | 
 |   clang::Expr *AlignOp = TheCall->getArg(1); | 
 |   if (!IsValidIntegerType(AlignOp->getType())) { | 
 |     S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int) | 
 |         << AlignOp->getType(); | 
 |     return true; | 
 |   } | 
 |   Expr::EvalResult AlignResult; | 
 |   unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1; | 
 |   // We can't check validity of alignment if it is value dependent. | 
 |   if (!AlignOp->isValueDependent() && | 
 |       AlignOp->EvaluateAsInt(AlignResult, S.Context, | 
 |                              Expr::SE_AllowSideEffects)) { | 
 |     llvm::APSInt AlignValue = AlignResult.Val.getInt(); | 
 |     llvm::APSInt MaxValue( | 
 |         llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits)); | 
 |     if (AlignValue < 1) { | 
 |       S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1; | 
 |       return true; | 
 |     } | 
 |     if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) { | 
 |       S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big) | 
 |           << toString(MaxValue, 10); | 
 |       return true; | 
 |     } | 
 |     if (!AlignValue.isPowerOf2()) { | 
 |       S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two); | 
 |       return true; | 
 |     } | 
 |     if (AlignValue == 1) { | 
 |       S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless) | 
 |           << IsBooleanAlignBuiltin; | 
 |     } | 
 |   } | 
 |  | 
 |   ExprResult SrcArg = S.PerformCopyInitialization( | 
 |       InitializedEntity::InitializeParameter(S.Context, SrcTy, false), | 
 |       SourceLocation(), Source); | 
 |   if (SrcArg.isInvalid()) | 
 |     return true; | 
 |   TheCall->setArg(0, SrcArg.get()); | 
 |   ExprResult AlignArg = | 
 |       S.PerformCopyInitialization(InitializedEntity::InitializeParameter( | 
 |                                       S.Context, AlignOp->getType(), false), | 
 |                                   SourceLocation(), AlignOp); | 
 |   if (AlignArg.isInvalid()) | 
 |     return true; | 
 |   TheCall->setArg(1, AlignArg.get()); | 
 |   // For align_up/align_down, the return type is the same as the (potentially | 
 |   // decayed) argument type including qualifiers. For is_aligned(), the result | 
 |   // is always bool. | 
 |   TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy); | 
 |   return false; | 
 | } | 
 |  | 
 | static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) { | 
 |   if (S.checkArgCount(TheCall, 3)) | 
 |     return true; | 
 |  | 
 |   std::pair<unsigned, const char *> Builtins[] = { | 
 |     { Builtin::BI__builtin_add_overflow, "ckd_add" }, | 
 |     { Builtin::BI__builtin_sub_overflow, "ckd_sub" }, | 
 |     { Builtin::BI__builtin_mul_overflow, "ckd_mul" }, | 
 |   }; | 
 |  | 
 |   bool CkdOperation = llvm::any_of(Builtins, [&](const std::pair<unsigned, | 
 |     const char *> &P) { | 
 |     return BuiltinID == P.first && TheCall->getExprLoc().isMacroID() && | 
 |          Lexer::getImmediateMacroName(TheCall->getExprLoc(), | 
 |          S.getSourceManager(), S.getLangOpts()) == P.second; | 
 |   }); | 
 |  | 
 |   auto ValidCkdIntType = [](QualType QT) { | 
 |     // A valid checked integer type is an integer type other than a plain char, | 
 |     // bool, a bit-precise type, or an enumeration type. | 
 |     if (const auto *BT = QT.getCanonicalType()->getAs<BuiltinType>()) | 
 |       return (BT->getKind() >= BuiltinType::Short && | 
 |            BT->getKind() <= BuiltinType::Int128) || ( | 
 |            BT->getKind() >= BuiltinType::UShort && | 
 |            BT->getKind() <= BuiltinType::UInt128) || | 
 |            BT->getKind() == BuiltinType::UChar || | 
 |            BT->getKind() == BuiltinType::SChar; | 
 |     return false; | 
 |   }; | 
 |  | 
 |   // First two arguments should be integers. | 
 |   for (unsigned I = 0; I < 2; ++I) { | 
 |     ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(I)); | 
 |     if (Arg.isInvalid()) return true; | 
 |     TheCall->setArg(I, Arg.get()); | 
 |  | 
 |     QualType Ty = Arg.get()->getType(); | 
 |     bool IsValid = CkdOperation ? ValidCkdIntType(Ty) : Ty->isIntegerType(); | 
 |     if (!IsValid) { | 
 |       S.Diag(Arg.get()->getBeginLoc(), diag::err_overflow_builtin_must_be_int) | 
 |           << CkdOperation << Ty << Arg.get()->getSourceRange(); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   // Third argument should be a pointer to a non-const integer. | 
 |   // IRGen correctly handles volatile, restrict, and address spaces, and | 
 |   // the other qualifiers aren't possible. | 
 |   { | 
 |     ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2)); | 
 |     if (Arg.isInvalid()) return true; | 
 |     TheCall->setArg(2, Arg.get()); | 
 |  | 
 |     QualType Ty = Arg.get()->getType(); | 
 |     const auto *PtrTy = Ty->getAs<PointerType>(); | 
 |     if (!PtrTy || | 
 |         !PtrTy->getPointeeType()->isIntegerType() || | 
 |         (!ValidCkdIntType(PtrTy->getPointeeType()) && CkdOperation) || | 
 |         PtrTy->getPointeeType().isConstQualified()) { | 
 |       S.Diag(Arg.get()->getBeginLoc(), | 
 |              diag::err_overflow_builtin_must_be_ptr_int) | 
 |         << CkdOperation << Ty << Arg.get()->getSourceRange(); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   // Disallow signed bit-precise integer args larger than 128 bits to mul | 
 |   // function until we improve backend support. | 
 |   if (BuiltinID == Builtin::BI__builtin_mul_overflow) { | 
 |     for (unsigned I = 0; I < 3; ++I) { | 
 |       const auto Arg = TheCall->getArg(I); | 
 |       // Third argument will be a pointer. | 
 |       auto Ty = I < 2 ? Arg->getType() : Arg->getType()->getPointeeType(); | 
 |       if (Ty->isBitIntType() && Ty->isSignedIntegerType() && | 
 |           S.getASTContext().getIntWidth(Ty) > 128) | 
 |         return S.Diag(Arg->getBeginLoc(), | 
 |                       diag::err_overflow_builtin_bit_int_max_size) | 
 |                << 128; | 
 |     } | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | namespace { | 
 | struct BuiltinDumpStructGenerator { | 
 |   Sema &S; | 
 |   CallExpr *TheCall; | 
 |   SourceLocation Loc = TheCall->getBeginLoc(); | 
 |   SmallVector<Expr *, 32> Actions; | 
 |   DiagnosticErrorTrap ErrorTracker; | 
 |   PrintingPolicy Policy; | 
 |  | 
 |   BuiltinDumpStructGenerator(Sema &S, CallExpr *TheCall) | 
 |       : S(S), TheCall(TheCall), ErrorTracker(S.getDiagnostics()), | 
 |         Policy(S.Context.getPrintingPolicy()) { | 
 |     Policy.AnonymousTagLocations = false; | 
 |   } | 
 |  | 
 |   Expr *makeOpaqueValueExpr(Expr *Inner) { | 
 |     auto *OVE = new (S.Context) | 
 |         OpaqueValueExpr(Loc, Inner->getType(), Inner->getValueKind(), | 
 |                         Inner->getObjectKind(), Inner); | 
 |     Actions.push_back(OVE); | 
 |     return OVE; | 
 |   } | 
 |  | 
 |   Expr *getStringLiteral(llvm::StringRef Str) { | 
 |     Expr *Lit = S.Context.getPredefinedStringLiteralFromCache(Str); | 
 |     // Wrap the literal in parentheses to attach a source location. | 
 |     return new (S.Context) ParenExpr(Loc, Loc, Lit); | 
 |   } | 
 |  | 
 |   bool callPrintFunction(llvm::StringRef Format, | 
 |                          llvm::ArrayRef<Expr *> Exprs = {}) { | 
 |     SmallVector<Expr *, 8> Args; | 
 |     assert(TheCall->getNumArgs() >= 2); | 
 |     Args.reserve((TheCall->getNumArgs() - 2) + /*Format*/ 1 + Exprs.size()); | 
 |     Args.assign(TheCall->arg_begin() + 2, TheCall->arg_end()); | 
 |     Args.push_back(getStringLiteral(Format)); | 
 |     llvm::append_range(Args, Exprs); | 
 |  | 
 |     // Register a note to explain why we're performing the call. | 
 |     Sema::CodeSynthesisContext Ctx; | 
 |     Ctx.Kind = Sema::CodeSynthesisContext::BuildingBuiltinDumpStructCall; | 
 |     Ctx.PointOfInstantiation = Loc; | 
 |     Ctx.CallArgs = Args.data(); | 
 |     Ctx.NumCallArgs = Args.size(); | 
 |     S.pushCodeSynthesisContext(Ctx); | 
 |  | 
 |     ExprResult RealCall = | 
 |         S.BuildCallExpr(/*Scope=*/nullptr, TheCall->getArg(1), | 
 |                         TheCall->getBeginLoc(), Args, TheCall->getRParenLoc()); | 
 |  | 
 |     S.popCodeSynthesisContext(); | 
 |     if (!RealCall.isInvalid()) | 
 |       Actions.push_back(RealCall.get()); | 
 |     // Bail out if we've hit any errors, even if we managed to build the | 
 |     // call. We don't want to produce more than one error. | 
 |     return RealCall.isInvalid() || ErrorTracker.hasErrorOccurred(); | 
 |   } | 
 |  | 
 |   Expr *getIndentString(unsigned Depth) { | 
 |     if (!Depth) | 
 |       return nullptr; | 
 |  | 
 |     llvm::SmallString<32> Indent; | 
 |     Indent.resize(Depth * Policy.Indentation, ' '); | 
 |     return getStringLiteral(Indent); | 
 |   } | 
 |  | 
 |   Expr *getTypeString(QualType T) { | 
 |     return getStringLiteral(T.getAsString(Policy)); | 
 |   } | 
 |  | 
 |   bool appendFormatSpecifier(QualType T, llvm::SmallVectorImpl<char> &Str) { | 
 |     llvm::raw_svector_ostream OS(Str); | 
 |  | 
 |     // Format 'bool', 'char', 'signed char', 'unsigned char' as numbers, rather | 
 |     // than trying to print a single character. | 
 |     if (auto *BT = T->getAs<BuiltinType>()) { | 
 |       switch (BT->getKind()) { | 
 |       case BuiltinType::Bool: | 
 |         OS << "%d"; | 
 |         return true; | 
 |       case BuiltinType::Char_U: | 
 |       case BuiltinType::UChar: | 
 |         OS << "%hhu"; | 
 |         return true; | 
 |       case BuiltinType::Char_S: | 
 |       case BuiltinType::SChar: | 
 |         OS << "%hhd"; | 
 |         return true; | 
 |       default: | 
 |         break; | 
 |       } | 
 |     } | 
 |  | 
 |     analyze_printf::PrintfSpecifier Specifier; | 
 |     if (Specifier.fixType(T, S.getLangOpts(), S.Context, /*IsObjCLiteral=*/false)) { | 
 |       // We were able to guess how to format this. | 
 |       if (Specifier.getConversionSpecifier().getKind() == | 
 |           analyze_printf::PrintfConversionSpecifier::sArg) { | 
 |         // Wrap double-quotes around a '%s' specifier and limit its maximum | 
 |         // length. Ideally we'd also somehow escape special characters in the | 
 |         // contents but printf doesn't support that. | 
 |         // FIXME: '%s' formatting is not safe in general. | 
 |         OS << '"'; | 
 |         Specifier.setPrecision(analyze_printf::OptionalAmount(32u)); | 
 |         Specifier.toString(OS); | 
 |         OS << '"'; | 
 |         // FIXME: It would be nice to include a '...' if the string doesn't fit | 
 |         // in the length limit. | 
 |       } else { | 
 |         Specifier.toString(OS); | 
 |       } | 
 |       return true; | 
 |     } | 
 |  | 
 |     if (T->isPointerType()) { | 
 |       // Format all pointers with '%p'. | 
 |       OS << "%p"; | 
 |       return true; | 
 |     } | 
 |  | 
 |     return false; | 
 |   } | 
 |  | 
 |   bool dumpUnnamedRecord(const RecordDecl *RD, Expr *E, unsigned Depth) { | 
 |     Expr *IndentLit = getIndentString(Depth); | 
 |     Expr *TypeLit = getTypeString(S.Context.getCanonicalTagType(RD)); | 
 |     if (IndentLit ? callPrintFunction("%s%s", {IndentLit, TypeLit}) | 
 |                   : callPrintFunction("%s", {TypeLit})) | 
 |       return true; | 
 |  | 
 |     return dumpRecordValue(RD, E, IndentLit, Depth); | 
 |   } | 
 |  | 
 |   // Dump a record value. E should be a pointer or lvalue referring to an RD. | 
 |   bool dumpRecordValue(const RecordDecl *RD, Expr *E, Expr *RecordIndent, | 
 |                        unsigned Depth) { | 
 |     // FIXME: Decide what to do if RD is a union. At least we should probably | 
 |     // turn off printing `const char*` members with `%s`, because that is very | 
 |     // likely to crash if that's not the active member. Whatever we decide, we | 
 |     // should document it. | 
 |  | 
 |     // Build an OpaqueValueExpr so we can refer to E more than once without | 
 |     // triggering re-evaluation. | 
 |     Expr *RecordArg = makeOpaqueValueExpr(E); | 
 |     bool RecordArgIsPtr = RecordArg->getType()->isPointerType(); | 
 |  | 
 |     if (callPrintFunction(" {\n")) | 
 |       return true; | 
 |  | 
 |     // Dump each base class, regardless of whether they're aggregates. | 
 |     if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { | 
 |       for (const auto &Base : CXXRD->bases()) { | 
 |         QualType BaseType = | 
 |             RecordArgIsPtr ? S.Context.getPointerType(Base.getType()) | 
 |                            : S.Context.getLValueReferenceType(Base.getType()); | 
 |         ExprResult BasePtr = S.BuildCStyleCastExpr( | 
 |             Loc, S.Context.getTrivialTypeSourceInfo(BaseType, Loc), Loc, | 
 |             RecordArg); | 
 |         if (BasePtr.isInvalid() || | 
 |             dumpUnnamedRecord(Base.getType()->getAsRecordDecl(), BasePtr.get(), | 
 |                               Depth + 1)) | 
 |           return true; | 
 |       } | 
 |     } | 
 |  | 
 |     Expr *FieldIndentArg = getIndentString(Depth + 1); | 
 |  | 
 |     // Dump each field. | 
 |     for (auto *D : RD->decls()) { | 
 |       auto *IFD = dyn_cast<IndirectFieldDecl>(D); | 
 |       auto *FD = IFD ? IFD->getAnonField() : dyn_cast<FieldDecl>(D); | 
 |       if (!FD || FD->isUnnamedBitField() || FD->isAnonymousStructOrUnion()) | 
 |         continue; | 
 |  | 
 |       llvm::SmallString<20> Format = llvm::StringRef("%s%s %s "); | 
 |       llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg, | 
 |                                            getTypeString(FD->getType()), | 
 |                                            getStringLiteral(FD->getName())}; | 
 |  | 
 |       if (FD->isBitField()) { | 
 |         Format += ": %zu "; | 
 |         QualType SizeT = S.Context.getSizeType(); | 
 |         llvm::APInt BitWidth(S.Context.getIntWidth(SizeT), | 
 |                              FD->getBitWidthValue()); | 
 |         Args.push_back(IntegerLiteral::Create(S.Context, BitWidth, SizeT, Loc)); | 
 |       } | 
 |  | 
 |       Format += "="; | 
 |  | 
 |       ExprResult Field = | 
 |           IFD ? S.BuildAnonymousStructUnionMemberReference( | 
 |                     CXXScopeSpec(), Loc, IFD, | 
 |                     DeclAccessPair::make(IFD, AS_public), RecordArg, Loc) | 
 |               : S.BuildFieldReferenceExpr( | 
 |                     RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD, | 
 |                     DeclAccessPair::make(FD, AS_public), | 
 |                     DeclarationNameInfo(FD->getDeclName(), Loc)); | 
 |       if (Field.isInvalid()) | 
 |         return true; | 
 |  | 
 |       auto *InnerRD = FD->getType()->getAsRecordDecl(); | 
 |       auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD); | 
 |       if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) { | 
 |         // Recursively print the values of members of aggregate record type. | 
 |         if (callPrintFunction(Format, Args) || | 
 |             dumpRecordValue(InnerRD, Field.get(), FieldIndentArg, Depth + 1)) | 
 |           return true; | 
 |       } else { | 
 |         Format += " "; | 
 |         if (appendFormatSpecifier(FD->getType(), Format)) { | 
 |           // We know how to print this field. | 
 |           Args.push_back(Field.get()); | 
 |         } else { | 
 |           // We don't know how to print this field. Print out its address | 
 |           // with a format specifier that a smart tool will be able to | 
 |           // recognize and treat specially. | 
 |           Format += "*%p"; | 
 |           ExprResult FieldAddr = | 
 |               S.BuildUnaryOp(nullptr, Loc, UO_AddrOf, Field.get()); | 
 |           if (FieldAddr.isInvalid()) | 
 |             return true; | 
 |           Args.push_back(FieldAddr.get()); | 
 |         } | 
 |         Format += "\n"; | 
 |         if (callPrintFunction(Format, Args)) | 
 |           return true; | 
 |       } | 
 |     } | 
 |  | 
 |     return RecordIndent ? callPrintFunction("%s}\n", RecordIndent) | 
 |                         : callPrintFunction("}\n"); | 
 |   } | 
 |  | 
 |   Expr *buildWrapper() { | 
 |     auto *Wrapper = PseudoObjectExpr::Create(S.Context, TheCall, Actions, | 
 |                                              PseudoObjectExpr::NoResult); | 
 |     TheCall->setType(Wrapper->getType()); | 
 |     TheCall->setValueKind(Wrapper->getValueKind()); | 
 |     return Wrapper; | 
 |   } | 
 | }; | 
 | } // namespace | 
 |  | 
 | static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCountAtLeast(TheCall, 2)) | 
 |     return ExprError(); | 
 |  | 
 |   ExprResult PtrArgResult = S.DefaultLvalueConversion(TheCall->getArg(0)); | 
 |   if (PtrArgResult.isInvalid()) | 
 |     return ExprError(); | 
 |   TheCall->setArg(0, PtrArgResult.get()); | 
 |  | 
 |   // First argument should be a pointer to a struct. | 
 |   QualType PtrArgType = PtrArgResult.get()->getType(); | 
 |   if (!PtrArgType->isPointerType() || | 
 |       !PtrArgType->getPointeeType()->isRecordType()) { | 
 |     S.Diag(PtrArgResult.get()->getBeginLoc(), | 
 |            diag::err_expected_struct_pointer_argument) | 
 |         << 1 << TheCall->getDirectCallee() << PtrArgType; | 
 |     return ExprError(); | 
 |   } | 
 |   QualType Pointee = PtrArgType->getPointeeType(); | 
 |   const RecordDecl *RD = Pointee->getAsRecordDecl(); | 
 |   // Try to instantiate the class template as appropriate; otherwise, access to | 
 |   // its data() may lead to a crash. | 
 |   if (S.RequireCompleteType(PtrArgResult.get()->getBeginLoc(), Pointee, | 
 |                             diag::err_incomplete_type)) | 
 |     return ExprError(); | 
 |   // Second argument is a callable, but we can't fully validate it until we try | 
 |   // calling it. | 
 |   QualType FnArgType = TheCall->getArg(1)->getType(); | 
 |   if (!FnArgType->isFunctionType() && !FnArgType->isFunctionPointerType() && | 
 |       !FnArgType->isBlockPointerType() && | 
 |       !(S.getLangOpts().CPlusPlus && FnArgType->isRecordType())) { | 
 |     auto *BT = FnArgType->getAs<BuiltinType>(); | 
 |     switch (BT ? BT->getKind() : BuiltinType::Void) { | 
 |     case BuiltinType::Dependent: | 
 |     case BuiltinType::Overload: | 
 |     case BuiltinType::BoundMember: | 
 |     case BuiltinType::PseudoObject: | 
 |     case BuiltinType::UnknownAny: | 
 |     case BuiltinType::BuiltinFn: | 
 |       // This might be a callable. | 
 |       break; | 
 |  | 
 |     default: | 
 |       S.Diag(TheCall->getArg(1)->getBeginLoc(), | 
 |              diag::err_expected_callable_argument) | 
 |           << 2 << TheCall->getDirectCallee() << FnArgType; | 
 |       return ExprError(); | 
 |     } | 
 |   } | 
 |  | 
 |   BuiltinDumpStructGenerator Generator(S, TheCall); | 
 |  | 
 |   // Wrap parentheses around the given pointer. This is not necessary for | 
 |   // correct code generation, but it means that when we pretty-print the call | 
 |   // arguments in our diagnostics we will produce '(&s)->n' instead of the | 
 |   // incorrect '&s->n'. | 
 |   Expr *PtrArg = PtrArgResult.get(); | 
 |   PtrArg = new (S.Context) | 
 |       ParenExpr(PtrArg->getBeginLoc(), | 
 |                 S.getLocForEndOfToken(PtrArg->getEndLoc()), PtrArg); | 
 |   if (Generator.dumpUnnamedRecord(RD, PtrArg, 0)) | 
 |     return ExprError(); | 
 |  | 
 |   return Generator.buildWrapper(); | 
 | } | 
 |  | 
 | static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { | 
 |   if (S.checkArgCount(BuiltinCall, 2)) | 
 |     return true; | 
 |  | 
 |   SourceLocation BuiltinLoc = BuiltinCall->getBeginLoc(); | 
 |   Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts(); | 
 |   Expr *Call = BuiltinCall->getArg(0); | 
 |   Expr *Chain = BuiltinCall->getArg(1); | 
 |  | 
 |   if (Call->getStmtClass() != Stmt::CallExprClass) { | 
 |     S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call) | 
 |         << Call->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   auto CE = cast<CallExpr>(Call); | 
 |   if (CE->getCallee()->getType()->isBlockPointerType()) { | 
 |     S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call) | 
 |         << Call->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   const Decl *TargetDecl = CE->getCalleeDecl(); | 
 |   if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) | 
 |     if (FD->getBuiltinID()) { | 
 |       S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call) | 
 |           << Call->getSourceRange(); | 
 |       return true; | 
 |     } | 
 |  | 
 |   if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) { | 
 |     S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call) | 
 |         << Call->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   ExprResult ChainResult = S.UsualUnaryConversions(Chain); | 
 |   if (ChainResult.isInvalid()) | 
 |     return true; | 
 |   if (!ChainResult.get()->getType()->isPointerType()) { | 
 |     S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer) | 
 |         << Chain->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   QualType ReturnTy = CE->getCallReturnType(S.Context); | 
 |   QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() }; | 
 |   QualType BuiltinTy = S.Context.getFunctionType( | 
 |       ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo()); | 
 |   QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy); | 
 |  | 
 |   Builtin = | 
 |       S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get(); | 
 |  | 
 |   BuiltinCall->setType(CE->getType()); | 
 |   BuiltinCall->setValueKind(CE->getValueKind()); | 
 |   BuiltinCall->setObjectKind(CE->getObjectKind()); | 
 |   BuiltinCall->setCallee(Builtin); | 
 |   BuiltinCall->setArg(1, ChainResult.get()); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | class ScanfDiagnosticFormatHandler | 
 |     : public analyze_format_string::FormatStringHandler { | 
 |   // Accepts the argument index (relative to the first destination index) of the | 
 |   // argument whose size we want. | 
 |   using ComputeSizeFunction = | 
 |       llvm::function_ref<std::optional<llvm::APSInt>(unsigned)>; | 
 |  | 
 |   // Accepts the argument index (relative to the first destination index), the | 
 |   // destination size, and the source size). | 
 |   using DiagnoseFunction = | 
 |       llvm::function_ref<void(unsigned, unsigned, unsigned)>; | 
 |  | 
 |   ComputeSizeFunction ComputeSizeArgument; | 
 |   DiagnoseFunction Diagnose; | 
 |  | 
 | public: | 
 |   ScanfDiagnosticFormatHandler(ComputeSizeFunction ComputeSizeArgument, | 
 |                                DiagnoseFunction Diagnose) | 
 |       : ComputeSizeArgument(ComputeSizeArgument), Diagnose(Diagnose) {} | 
 |  | 
 |   bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, | 
 |                             const char *StartSpecifier, | 
 |                             unsigned specifierLen) override { | 
 |     if (!FS.consumesDataArgument()) | 
 |       return true; | 
 |  | 
 |     unsigned NulByte = 0; | 
 |     switch ((FS.getConversionSpecifier().getKind())) { | 
 |     default: | 
 |       return true; | 
 |     case analyze_format_string::ConversionSpecifier::sArg: | 
 |     case analyze_format_string::ConversionSpecifier::ScanListArg: | 
 |       NulByte = 1; | 
 |       break; | 
 |     case analyze_format_string::ConversionSpecifier::cArg: | 
 |       break; | 
 |     } | 
 |  | 
 |     analyze_format_string::OptionalAmount FW = FS.getFieldWidth(); | 
 |     if (FW.getHowSpecified() != | 
 |         analyze_format_string::OptionalAmount::HowSpecified::Constant) | 
 |       return true; | 
 |  | 
 |     unsigned SourceSize = FW.getConstantAmount() + NulByte; | 
 |  | 
 |     std::optional<llvm::APSInt> DestSizeAPS = | 
 |         ComputeSizeArgument(FS.getArgIndex()); | 
 |     if (!DestSizeAPS) | 
 |       return true; | 
 |  | 
 |     unsigned DestSize = DestSizeAPS->getZExtValue(); | 
 |  | 
 |     if (DestSize < SourceSize) | 
 |       Diagnose(FS.getArgIndex(), DestSize, SourceSize); | 
 |  | 
 |     return true; | 
 |   } | 
 | }; | 
 |  | 
 | class EstimateSizeFormatHandler | 
 |     : public analyze_format_string::FormatStringHandler { | 
 |   size_t Size; | 
 |   /// Whether the format string contains Linux kernel's format specifier | 
 |   /// extension. | 
 |   bool IsKernelCompatible = true; | 
 |  | 
 | public: | 
 |   EstimateSizeFormatHandler(StringRef Format) | 
 |       : Size(std::min(Format.find(0), Format.size()) + | 
 |              1 /* null byte always written by sprintf */) {} | 
 |  | 
 |   bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, | 
 |                              const char *, unsigned SpecifierLen, | 
 |                              const TargetInfo &) override { | 
 |  | 
 |     const size_t FieldWidth = computeFieldWidth(FS); | 
 |     const size_t Precision = computePrecision(FS); | 
 |  | 
 |     // The actual format. | 
 |     switch (FS.getConversionSpecifier().getKind()) { | 
 |     // Just a char. | 
 |     case analyze_format_string::ConversionSpecifier::cArg: | 
 |     case analyze_format_string::ConversionSpecifier::CArg: | 
 |       Size += std::max(FieldWidth, (size_t)1); | 
 |       break; | 
 |     // Just an integer. | 
 |     case analyze_format_string::ConversionSpecifier::dArg: | 
 |     case analyze_format_string::ConversionSpecifier::DArg: | 
 |     case analyze_format_string::ConversionSpecifier::iArg: | 
 |     case analyze_format_string::ConversionSpecifier::oArg: | 
 |     case analyze_format_string::ConversionSpecifier::OArg: | 
 |     case analyze_format_string::ConversionSpecifier::uArg: | 
 |     case analyze_format_string::ConversionSpecifier::UArg: | 
 |     case analyze_format_string::ConversionSpecifier::xArg: | 
 |     case analyze_format_string::ConversionSpecifier::XArg: | 
 |       Size += std::max(FieldWidth, Precision); | 
 |       break; | 
 |  | 
 |     // %g style conversion switches between %f or %e style dynamically. | 
 |     // %g removes trailing zeros, and does not print decimal point if there are | 
 |     // no digits that follow it. Thus %g can print a single digit. | 
 |     // FIXME: If it is alternative form: | 
 |     // For g and G conversions, trailing zeros are not removed from the result. | 
 |     case analyze_format_string::ConversionSpecifier::gArg: | 
 |     case analyze_format_string::ConversionSpecifier::GArg: | 
 |       Size += 1; | 
 |       break; | 
 |  | 
 |     // Floating point number in the form '[+]ddd.ddd'. | 
 |     case analyze_format_string::ConversionSpecifier::fArg: | 
 |     case analyze_format_string::ConversionSpecifier::FArg: | 
 |       Size += std::max(FieldWidth, 1 /* integer part */ + | 
 |                                        (Precision ? 1 + Precision | 
 |                                                   : 0) /* period + decimal */); | 
 |       break; | 
 |  | 
 |     // Floating point number in the form '[-]d.ddde[+-]dd'. | 
 |     case analyze_format_string::ConversionSpecifier::eArg: | 
 |     case analyze_format_string::ConversionSpecifier::EArg: | 
 |       Size += | 
 |           std::max(FieldWidth, | 
 |                    1 /* integer part */ + | 
 |                        (Precision ? 1 + Precision : 0) /* period + decimal */ + | 
 |                        1 /* e or E letter */ + 2 /* exponent */); | 
 |       break; | 
 |  | 
 |     // Floating point number in the form '[-]0xh.hhhhp±dd'. | 
 |     case analyze_format_string::ConversionSpecifier::aArg: | 
 |     case analyze_format_string::ConversionSpecifier::AArg: | 
 |       Size += | 
 |           std::max(FieldWidth, | 
 |                    2 /* 0x */ + 1 /* integer part */ + | 
 |                        (Precision ? 1 + Precision : 0) /* period + decimal */ + | 
 |                        1 /* p or P letter */ + 1 /* + or - */ + 1 /* value */); | 
 |       break; | 
 |  | 
 |     // Just a string. | 
 |     case analyze_format_string::ConversionSpecifier::sArg: | 
 |     case analyze_format_string::ConversionSpecifier::SArg: | 
 |       Size += FieldWidth; | 
 |       break; | 
 |  | 
 |     // Just a pointer in the form '0xddd'. | 
 |     case analyze_format_string::ConversionSpecifier::pArg: | 
 |       // Linux kernel has its own extesion for `%p` specifier. | 
 |       // Kernel Document: | 
 |       // https://docs.kernel.org/core-api/printk-formats.html#pointer-types | 
 |       IsKernelCompatible = false; | 
 |       Size += std::max(FieldWidth, 2 /* leading 0x */ + Precision); | 
 |       break; | 
 |  | 
 |     // A plain percent. | 
 |     case analyze_format_string::ConversionSpecifier::PercentArg: | 
 |       Size += 1; | 
 |       break; | 
 |  | 
 |     default: | 
 |       break; | 
 |     } | 
 |  | 
 |     // If field width is specified, the sign/space is already accounted for | 
 |     // within the field width, so no additional size is needed. | 
 |     if ((FS.hasPlusPrefix() || FS.hasSpacePrefix()) && FieldWidth == 0) | 
 |       Size += 1; | 
 |  | 
 |     if (FS.hasAlternativeForm()) { | 
 |       switch (FS.getConversionSpecifier().getKind()) { | 
 |       // For o conversion, it increases the precision, if and only if necessary, | 
 |       // to force the first digit of the result to be a zero | 
 |       // (if the value and precision are both 0, a single 0 is printed) | 
 |       case analyze_format_string::ConversionSpecifier::oArg: | 
 |       // For b conversion, a nonzero result has 0b prefixed to it. | 
 |       case analyze_format_string::ConversionSpecifier::bArg: | 
 |       // For x (or X) conversion, a nonzero result has 0x (or 0X) prefixed to | 
 |       // it. | 
 |       case analyze_format_string::ConversionSpecifier::xArg: | 
 |       case analyze_format_string::ConversionSpecifier::XArg: | 
 |         // Note: even when the prefix is added, if | 
 |         // (prefix_width <= FieldWidth - formatted_length) holds, | 
 |         // the prefix does not increase the format | 
 |         // size. e.g.(("%#3x", 0xf) is "0xf") | 
 |  | 
 |         // If the result is zero, o, b, x, X adds nothing. | 
 |         break; | 
 |       // For a, A, e, E, f, F, g, and G conversions, | 
 |       // the result of converting a floating-point number always contains a | 
 |       // decimal-point | 
 |       case analyze_format_string::ConversionSpecifier::aArg: | 
 |       case analyze_format_string::ConversionSpecifier::AArg: | 
 |       case analyze_format_string::ConversionSpecifier::eArg: | 
 |       case analyze_format_string::ConversionSpecifier::EArg: | 
 |       case analyze_format_string::ConversionSpecifier::fArg: | 
 |       case analyze_format_string::ConversionSpecifier::FArg: | 
 |       case analyze_format_string::ConversionSpecifier::gArg: | 
 |       case analyze_format_string::ConversionSpecifier::GArg: | 
 |         Size += (Precision ? 0 : 1); | 
 |         break; | 
 |       // For other conversions, the behavior is undefined. | 
 |       default: | 
 |         break; | 
 |       } | 
 |     } | 
 |     assert(SpecifierLen <= Size && "no underflow"); | 
 |     Size -= SpecifierLen; | 
 |     return true; | 
 |   } | 
 |  | 
 |   size_t getSizeLowerBound() const { return Size; } | 
 |   bool isKernelCompatible() const { return IsKernelCompatible; } | 
 |  | 
 | private: | 
 |   static size_t computeFieldWidth(const analyze_printf::PrintfSpecifier &FS) { | 
 |     const analyze_format_string::OptionalAmount &FW = FS.getFieldWidth(); | 
 |     size_t FieldWidth = 0; | 
 |     if (FW.getHowSpecified() == analyze_format_string::OptionalAmount::Constant) | 
 |       FieldWidth = FW.getConstantAmount(); | 
 |     return FieldWidth; | 
 |   } | 
 |  | 
 |   static size_t computePrecision(const analyze_printf::PrintfSpecifier &FS) { | 
 |     const analyze_format_string::OptionalAmount &FW = FS.getPrecision(); | 
 |     size_t Precision = 0; | 
 |  | 
 |     // See man 3 printf for default precision value based on the specifier. | 
 |     switch (FW.getHowSpecified()) { | 
 |     case analyze_format_string::OptionalAmount::NotSpecified: | 
 |       switch (FS.getConversionSpecifier().getKind()) { | 
 |       default: | 
 |         break; | 
 |       case analyze_format_string::ConversionSpecifier::dArg: // %d | 
 |       case analyze_format_string::ConversionSpecifier::DArg: // %D | 
 |       case analyze_format_string::ConversionSpecifier::iArg: // %i | 
 |         Precision = 1; | 
 |         break; | 
 |       case analyze_format_string::ConversionSpecifier::oArg: // %d | 
 |       case analyze_format_string::ConversionSpecifier::OArg: // %D | 
 |       case analyze_format_string::ConversionSpecifier::uArg: // %d | 
 |       case analyze_format_string::ConversionSpecifier::UArg: // %D | 
 |       case analyze_format_string::ConversionSpecifier::xArg: // %d | 
 |       case analyze_format_string::ConversionSpecifier::XArg: // %D | 
 |         Precision = 1; | 
 |         break; | 
 |       case analyze_format_string::ConversionSpecifier::fArg: // %f | 
 |       case analyze_format_string::ConversionSpecifier::FArg: // %F | 
 |       case analyze_format_string::ConversionSpecifier::eArg: // %e | 
 |       case analyze_format_string::ConversionSpecifier::EArg: // %E | 
 |       case analyze_format_string::ConversionSpecifier::gArg: // %g | 
 |       case analyze_format_string::ConversionSpecifier::GArg: // %G | 
 |         Precision = 6; | 
 |         break; | 
 |       case analyze_format_string::ConversionSpecifier::pArg: // %d | 
 |         Precision = 1; | 
 |         break; | 
 |       } | 
 |       break; | 
 |     case analyze_format_string::OptionalAmount::Constant: | 
 |       Precision = FW.getConstantAmount(); | 
 |       break; | 
 |     default: | 
 |       break; | 
 |     } | 
 |     return Precision; | 
 |   } | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | static bool ProcessFormatStringLiteral(const Expr *FormatExpr, | 
 |                                        StringRef &FormatStrRef, size_t &StrLen, | 
 |                                        ASTContext &Context) { | 
 |   if (const auto *Format = dyn_cast<StringLiteral>(FormatExpr); | 
 |       Format && (Format->isOrdinary() || Format->isUTF8())) { | 
 |     FormatStrRef = Format->getString(); | 
 |     const ConstantArrayType *T = | 
 |         Context.getAsConstantArrayType(Format->getType()); | 
 |     assert(T && "String literal not of constant array type!"); | 
 |     size_t TypeSize = T->getZExtSize(); | 
 |     // In case there's a null byte somewhere. | 
 |     StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0)); | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, | 
 |                                                CallExpr *TheCall) { | 
 |   if (TheCall->isValueDependent() || TheCall->isTypeDependent() || | 
 |       isConstantEvaluatedContext()) | 
 |     return; | 
 |  | 
 |   bool UseDABAttr = false; | 
 |   const FunctionDecl *UseDecl = FD; | 
 |  | 
 |   const auto *DABAttr = FD->getAttr<DiagnoseAsBuiltinAttr>(); | 
 |   if (DABAttr) { | 
 |     UseDecl = DABAttr->getFunction(); | 
 |     assert(UseDecl && "Missing FunctionDecl in DiagnoseAsBuiltin attribute!"); | 
 |     UseDABAttr = true; | 
 |   } | 
 |  | 
 |   unsigned BuiltinID = UseDecl->getBuiltinID(/*ConsiderWrappers=*/true); | 
 |  | 
 |   if (!BuiltinID) | 
 |     return; | 
 |  | 
 |   const TargetInfo &TI = getASTContext().getTargetInfo(); | 
 |   unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); | 
 |  | 
 |   auto TranslateIndex = [&](unsigned Index) -> std::optional<unsigned> { | 
 |     // If we refer to a diagnose_as_builtin attribute, we need to change the | 
 |     // argument index to refer to the arguments of the called function. Unless | 
 |     // the index is out of bounds, which presumably means it's a variadic | 
 |     // function. | 
 |     if (!UseDABAttr) | 
 |       return Index; | 
 |     unsigned DABIndices = DABAttr->argIndices_size(); | 
 |     unsigned NewIndex = Index < DABIndices | 
 |                             ? DABAttr->argIndices_begin()[Index] | 
 |                             : Index - DABIndices + FD->getNumParams(); | 
 |     if (NewIndex >= TheCall->getNumArgs()) | 
 |       return std::nullopt; | 
 |     return NewIndex; | 
 |   }; | 
 |  | 
 |   auto ComputeExplicitObjectSizeArgument = | 
 |       [&](unsigned Index) -> std::optional<llvm::APSInt> { | 
 |     std::optional<unsigned> IndexOptional = TranslateIndex(Index); | 
 |     if (!IndexOptional) | 
 |       return std::nullopt; | 
 |     unsigned NewIndex = *IndexOptional; | 
 |     Expr::EvalResult Result; | 
 |     Expr *SizeArg = TheCall->getArg(NewIndex); | 
 |     if (!SizeArg->EvaluateAsInt(Result, getASTContext())) | 
 |       return std::nullopt; | 
 |     llvm::APSInt Integer = Result.Val.getInt(); | 
 |     Integer.setIsUnsigned(true); | 
 |     return Integer; | 
 |   }; | 
 |  | 
 |   auto ComputeSizeArgument = | 
 |       [&](unsigned Index) -> std::optional<llvm::APSInt> { | 
 |     // 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; | 
 |     // This check can fail for variadic functions. | 
 |     if (Index < FD->getNumParams()) { | 
 |       if (const auto *POS = | 
 |               FD->getParamDecl(Index)->getAttr<PassObjectSizeAttr>()) | 
 |         BOSType = POS->getType(); | 
 |     } | 
 |  | 
 |     std::optional<unsigned> IndexOptional = TranslateIndex(Index); | 
 |     if (!IndexOptional) | 
 |       return std::nullopt; | 
 |     unsigned NewIndex = *IndexOptional; | 
 |  | 
 |     if (NewIndex >= TheCall->getNumArgs()) | 
 |       return std::nullopt; | 
 |  | 
 |     const Expr *ObjArg = TheCall->getArg(NewIndex); | 
 |     uint64_t Result; | 
 |     if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) | 
 |       return std::nullopt; | 
 |  | 
 |     // Get the object size in the target's size_t width. | 
 |     return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); | 
 |   }; | 
 |  | 
 |   auto ComputeStrLenArgument = | 
 |       [&](unsigned Index) -> std::optional<llvm::APSInt> { | 
 |     std::optional<unsigned> IndexOptional = TranslateIndex(Index); | 
 |     if (!IndexOptional) | 
 |       return std::nullopt; | 
 |     unsigned NewIndex = *IndexOptional; | 
 |  | 
 |     const Expr *ObjArg = TheCall->getArg(NewIndex); | 
 |     uint64_t Result; | 
 |     if (!ObjArg->tryEvaluateStrLen(Result, getASTContext())) | 
 |       return std::nullopt; | 
 |     // Add 1 for null byte. | 
 |     return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth); | 
 |   }; | 
 |  | 
 |   std::optional<llvm::APSInt> SourceSize; | 
 |   std::optional<llvm::APSInt> DestinationSize; | 
 |   unsigned DiagID = 0; | 
 |   bool IsChkVariant = false; | 
 |  | 
 |   auto GetFunctionName = [&]() { | 
 |     std::string FunctionNameStr = | 
 |         getASTContext().BuiltinInfo.getName(BuiltinID); | 
 |     llvm::StringRef FunctionName = FunctionNameStr; | 
 |     // Skim off the details of whichever builtin was called to produce a better | 
 |     // diagnostic, as it's unlikely that the user wrote the __builtin | 
 |     // explicitly. | 
 |     if (IsChkVariant) { | 
 |       FunctionName = FunctionName.drop_front(std::strlen("__builtin___")); | 
 |       FunctionName = FunctionName.drop_back(std::strlen("_chk")); | 
 |     } else { | 
 |       FunctionName.consume_front("__builtin_"); | 
 |     } | 
 |     return FunctionName.str(); | 
 |   }; | 
 |  | 
 |   switch (BuiltinID) { | 
 |   default: | 
 |     return; | 
 |   case Builtin::BI__builtin_stpcpy: | 
 |   case Builtin::BIstpcpy: | 
 |   case Builtin::BI__builtin_strcpy: | 
 |   case Builtin::BIstrcpy: { | 
 |     DiagID = diag::warn_fortify_strlen_overflow; | 
 |     SourceSize = ComputeStrLenArgument(1); | 
 |     DestinationSize = ComputeSizeArgument(0); | 
 |     break; | 
 |   } | 
 |  | 
 |   case Builtin::BI__builtin___stpcpy_chk: | 
 |   case Builtin::BI__builtin___strcpy_chk: { | 
 |     DiagID = diag::warn_fortify_strlen_overflow; | 
 |     SourceSize = ComputeStrLenArgument(1); | 
 |     DestinationSize = ComputeExplicitObjectSizeArgument(2); | 
 |     IsChkVariant = true; | 
 |     break; | 
 |   } | 
 |  | 
 |   case Builtin::BIscanf: | 
 |   case Builtin::BIfscanf: | 
 |   case Builtin::BIsscanf: { | 
 |     unsigned FormatIndex = 1; | 
 |     unsigned DataIndex = 2; | 
 |     if (BuiltinID == Builtin::BIscanf) { | 
 |       FormatIndex = 0; | 
 |       DataIndex = 1; | 
 |     } | 
 |  | 
 |     const auto *FormatExpr = | 
 |         TheCall->getArg(FormatIndex)->IgnoreParenImpCasts(); | 
 |  | 
 |     StringRef FormatStrRef; | 
 |     size_t StrLen; | 
 |     if (!ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) | 
 |       return; | 
 |  | 
 |     auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize, | 
 |                         unsigned SourceSize) { | 
 |       DiagID = diag::warn_fortify_scanf_overflow; | 
 |       unsigned Index = ArgIndex + DataIndex; | 
 |       std::string FunctionName = GetFunctionName(); | 
 |       DiagRuntimeBehavior(TheCall->getArg(Index)->getBeginLoc(), TheCall, | 
 |                           PDiag(DiagID) << FunctionName << (Index + 1) | 
 |                                         << DestSize << SourceSize); | 
 |     }; | 
 |  | 
 |     auto ShiftedComputeSizeArgument = [&](unsigned Index) { | 
 |       return ComputeSizeArgument(Index + DataIndex); | 
 |     }; | 
 |     ScanfDiagnosticFormatHandler H(ShiftedComputeSizeArgument, Diagnose); | 
 |     const char *FormatBytes = FormatStrRef.data(); | 
 |     analyze_format_string::ParseScanfString(H, FormatBytes, | 
 |                                             FormatBytes + StrLen, getLangOpts(), | 
 |                                             Context.getTargetInfo()); | 
 |  | 
 |     // Unlike the other cases, in this one we have already issued the diagnostic | 
 |     // here, so no need to continue (because unlike the other cases, here the | 
 |     // diagnostic refers to the argument number). | 
 |     return; | 
 |   } | 
 |  | 
 |   case Builtin::BIsprintf: | 
 |   case Builtin::BI__builtin___sprintf_chk: { | 
 |     size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3; | 
 |     auto *FormatExpr = TheCall->getArg(FormatIndex)->IgnoreParenImpCasts(); | 
 |  | 
 |     StringRef FormatStrRef; | 
 |     size_t StrLen; | 
 |     if (ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) { | 
 |       EstimateSizeFormatHandler H(FormatStrRef); | 
 |       const char *FormatBytes = FormatStrRef.data(); | 
 |       if (!analyze_format_string::ParsePrintfString( | 
 |               H, FormatBytes, FormatBytes + StrLen, getLangOpts(), | 
 |               Context.getTargetInfo(), false)) { | 
 |         DiagID = H.isKernelCompatible() | 
 |                      ? diag::warn_format_overflow | 
 |                      : diag::warn_format_overflow_non_kprintf; | 
 |         SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) | 
 |                          .extOrTrunc(SizeTypeWidth); | 
 |         if (BuiltinID == Builtin::BI__builtin___sprintf_chk) { | 
 |           DestinationSize = ComputeExplicitObjectSizeArgument(2); | 
 |           IsChkVariant = true; | 
 |         } else { | 
 |           DestinationSize = ComputeSizeArgument(0); | 
 |         } | 
 |         break; | 
 |       } | 
 |     } | 
 |     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: | 
 |   case Builtin::BI__builtin___mempcpy_chk: { | 
 |     DiagID = diag::warn_builtin_chk_overflow; | 
 |     SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2); | 
 |     DestinationSize = | 
 |         ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); | 
 |     IsChkVariant = true; | 
 |     break; | 
 |   } | 
 |  | 
 |   case Builtin::BI__builtin___snprintf_chk: | 
 |   case Builtin::BI__builtin___vsnprintf_chk: { | 
 |     DiagID = diag::warn_builtin_chk_overflow; | 
 |     SourceSize = ComputeExplicitObjectSizeArgument(1); | 
 |     DestinationSize = ComputeExplicitObjectSizeArgument(3); | 
 |     IsChkVariant = true; | 
 |     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; | 
 |     SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); | 
 |     DestinationSize = ComputeSizeArgument(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: | 
 |   case Builtin::BImempcpy: | 
 |   case Builtin::BI__builtin_mempcpy: { | 
 |     DiagID = diag::warn_fortify_source_overflow; | 
 |     SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); | 
 |     DestinationSize = ComputeSizeArgument(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; | 
 |     SourceSize = ComputeExplicitObjectSizeArgument(1); | 
 |     const auto *FormatExpr = TheCall->getArg(2)->IgnoreParenImpCasts(); | 
 |     StringRef FormatStrRef; | 
 |     size_t StrLen; | 
 |     if (SourceSize && | 
 |         ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) { | 
 |       EstimateSizeFormatHandler H(FormatStrRef); | 
 |       const char *FormatBytes = FormatStrRef.data(); | 
 |       if (!analyze_format_string::ParsePrintfString( | 
 |               H, FormatBytes, FormatBytes + StrLen, getLangOpts(), | 
 |               Context.getTargetInfo(), /*isFreeBSDKPrintf=*/false)) { | 
 |         llvm::APSInt FormatSize = | 
 |             llvm::APSInt::getUnsigned(H.getSizeLowerBound()) | 
 |                 .extOrTrunc(SizeTypeWidth); | 
 |         if (FormatSize > *SourceSize && *SourceSize != 0) { | 
 |           unsigned TruncationDiagID = | 
 |               H.isKernelCompatible() ? diag::warn_format_truncation | 
 |                                      : diag::warn_format_truncation_non_kprintf; | 
 |           SmallString<16> SpecifiedSizeStr; | 
 |           SmallString<16> FormatSizeStr; | 
 |           SourceSize->toString(SpecifiedSizeStr, /*Radix=*/10); | 
 |           FormatSize.toString(FormatSizeStr, /*Radix=*/10); | 
 |           DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, | 
 |                               PDiag(TruncationDiagID) | 
 |                                   << GetFunctionName() << SpecifiedSizeStr | 
 |                                   << FormatSizeStr); | 
 |         } | 
 |       } | 
 |     } | 
 |     DestinationSize = ComputeSizeArgument(0); | 
 |   } | 
 |   } | 
 |  | 
 |   if (!SourceSize || !DestinationSize || | 
 |       llvm::APSInt::compareValues(*SourceSize, *DestinationSize) <= 0) | 
 |     return; | 
 |  | 
 |   std::string FunctionName = GetFunctionName(); | 
 |  | 
 |   SmallString<16> DestinationStr; | 
 |   SmallString<16> SourceStr; | 
 |   DestinationSize->toString(DestinationStr, /*Radix=*/10); | 
 |   SourceSize->toString(SourceStr, /*Radix=*/10); | 
 |   DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, | 
 |                       PDiag(DiagID) | 
 |                           << FunctionName << DestinationStr << SourceStr); | 
 | } | 
 |  | 
 | static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, | 
 |                                  Scope::ScopeFlags NeededScopeFlags, | 
 |                                  unsigned DiagID) { | 
 |   // Scopes aren't available during instantiation. Fortunately, builtin | 
 |   // functions cannot be template args so they cannot be formed through template | 
 |   // instantiation. Therefore checking once during the parse is sufficient. | 
 |   if (SemaRef.inTemplateInstantiation()) | 
 |     return false; | 
 |  | 
 |   Scope *S = SemaRef.getCurScope(); | 
 |   while (S && !S->isSEHExceptScope()) | 
 |     S = S->getParent(); | 
 |   if (!S || !(S->getFlags() & NeededScopeFlags)) { | 
 |     auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); | 
 |     SemaRef.Diag(TheCall->getExprLoc(), DiagID) | 
 |         << DRE->getDecl()->getIdentifier(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | // In OpenCL, __builtin_alloca_* should return a pointer to address space | 
 | // that corresponds to the stack address space i.e private address space. | 
 | static void builtinAllocaAddrSpace(Sema &S, CallExpr *TheCall) { | 
 |   QualType RT = TheCall->getType(); | 
 |   assert((RT->isPointerType() && !(RT->getPointeeType().hasAddressSpace())) && | 
 |          "__builtin_alloca has invalid address space"); | 
 |  | 
 |   RT = RT->getPointeeType(); | 
 |   RT = S.Context.getAddrSpaceQualType(RT, LangAS::opencl_private); | 
 |   TheCall->setType(S.Context.getPointerType(RT)); | 
 | } | 
 |  | 
 | namespace { | 
 | enum PointerAuthOpKind { | 
 |   PAO_Strip, | 
 |   PAO_Sign, | 
 |   PAO_Auth, | 
 |   PAO_SignGeneric, | 
 |   PAO_Discriminator, | 
 |   PAO_BlendPointer, | 
 |   PAO_BlendInteger | 
 | }; | 
 | } | 
 |  | 
 | bool Sema::checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range) { | 
 |   if (getLangOpts().PointerAuthIntrinsics) | 
 |     return false; | 
 |  | 
 |   Diag(Loc, diag::err_ptrauth_disabled) << Range; | 
 |   return true; | 
 | } | 
 |  | 
 | static bool checkPointerAuthEnabled(Sema &S, Expr *E) { | 
 |   return S.checkPointerAuthEnabled(E->getExprLoc(), E->getSourceRange()); | 
 | } | 
 |  | 
 | static bool checkPointerAuthKey(Sema &S, Expr *&Arg) { | 
 |   // Convert it to type 'int'. | 
 |   if (convertArgumentToType(S, Arg, S.Context.IntTy)) | 
 |     return true; | 
 |  | 
 |   // Value-dependent expressions are okay; wait for template instantiation. | 
 |   if (Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   unsigned KeyValue; | 
 |   return S.checkConstantPointerAuthKey(Arg, KeyValue); | 
 | } | 
 |  | 
 | bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) { | 
 |   // Attempt to constant-evaluate the expression. | 
 |   std::optional<llvm::APSInt> KeyValue = Arg->getIntegerConstantExpr(Context); | 
 |   if (!KeyValue) { | 
 |     Diag(Arg->getExprLoc(), diag::err_expr_not_ice) | 
 |         << 0 << Arg->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Ask the target to validate the key parameter. | 
 |   if (!Context.getTargetInfo().validatePointerAuthKey(*KeyValue)) { | 
 |     llvm::SmallString<32> Value; | 
 |     { | 
 |       llvm::raw_svector_ostream Str(Value); | 
 |       Str << *KeyValue; | 
 |     } | 
 |  | 
 |     Diag(Arg->getExprLoc(), diag::err_ptrauth_invalid_key) | 
 |         << Value << Arg->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   Result = KeyValue->getZExtValue(); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg, | 
 |                                             PointerAuthDiscArgKind Kind, | 
 |                                             unsigned &IntVal) { | 
 |   if (!Arg) { | 
 |     IntVal = 0; | 
 |     return true; | 
 |   } | 
 |  | 
 |   std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context); | 
 |   if (!Result) { | 
 |     Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice); | 
 |     return false; | 
 |   } | 
 |  | 
 |   unsigned Max; | 
 |   bool IsAddrDiscArg = false; | 
 |  | 
 |   switch (Kind) { | 
 |   case PointerAuthDiscArgKind::Addr: | 
 |     Max = 1; | 
 |     IsAddrDiscArg = true; | 
 |     break; | 
 |   case PointerAuthDiscArgKind::Extra: | 
 |     Max = PointerAuthQualifier::MaxDiscriminator; | 
 |     break; | 
 |   }; | 
 |  | 
 |   if (*Result < 0 || *Result > Max) { | 
 |     if (IsAddrDiscArg) | 
 |       Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid) | 
 |           << Result->getExtValue(); | 
 |     else | 
 |       Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid) | 
 |           << Result->getExtValue() << Max; | 
 |  | 
 |     return false; | 
 |   }; | 
 |  | 
 |   IntVal = Result->getZExtValue(); | 
 |   return true; | 
 | } | 
 |  | 
 | static std::pair<const ValueDecl *, CharUnits> | 
 | findConstantBaseAndOffset(Sema &S, Expr *E) { | 
 |   // Must evaluate as a pointer. | 
 |   Expr::EvalResult Result; | 
 |   if (!E->EvaluateAsRValue(Result, S.Context) || !Result.Val.isLValue()) | 
 |     return {nullptr, CharUnits()}; | 
 |  | 
 |   const auto *BaseDecl = | 
 |       Result.Val.getLValueBase().dyn_cast<const ValueDecl *>(); | 
 |   if (!BaseDecl) | 
 |     return {nullptr, CharUnits()}; | 
 |  | 
 |   return {BaseDecl, Result.Val.getLValueOffset()}; | 
 | } | 
 |  | 
 | static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind, | 
 |                                   bool RequireConstant = false) { | 
 |   if (Arg->hasPlaceholderType()) { | 
 |     ExprResult R = S.CheckPlaceholderExpr(Arg); | 
 |     if (R.isInvalid()) | 
 |       return true; | 
 |     Arg = R.get(); | 
 |   } | 
 |  | 
 |   auto AllowsPointer = [](PointerAuthOpKind OpKind) { | 
 |     return OpKind != PAO_BlendInteger; | 
 |   }; | 
 |   auto AllowsInteger = [](PointerAuthOpKind OpKind) { | 
 |     return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger || | 
 |            OpKind == PAO_SignGeneric; | 
 |   }; | 
 |  | 
 |   // Require the value to have the right range of type. | 
 |   QualType ExpectedTy; | 
 |   if (AllowsPointer(OpKind) && Arg->getType()->isPointerType()) { | 
 |     ExpectedTy = Arg->getType().getUnqualifiedType(); | 
 |   } else if (AllowsPointer(OpKind) && Arg->getType()->isNullPtrType()) { | 
 |     ExpectedTy = S.Context.VoidPtrTy; | 
 |   } else if (AllowsInteger(OpKind) && | 
 |              Arg->getType()->isIntegralOrUnscopedEnumerationType()) { | 
 |     ExpectedTy = S.Context.getUIntPtrType(); | 
 |  | 
 |   } else { | 
 |     // Diagnose the failures. | 
 |     S.Diag(Arg->getExprLoc(), diag::err_ptrauth_value_bad_type) | 
 |         << unsigned(OpKind == PAO_Discriminator  ? 1 | 
 |                     : OpKind == PAO_BlendPointer ? 2 | 
 |                     : OpKind == PAO_BlendInteger ? 3 | 
 |                                                  : 0) | 
 |         << unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0) | 
 |         << Arg->getType() << Arg->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Convert to that type.  This should just be an lvalue-to-rvalue | 
 |   // conversion. | 
 |   if (convertArgumentToType(S, Arg, ExpectedTy)) | 
 |     return true; | 
 |  | 
 |   if (!RequireConstant) { | 
 |     // Warn about null pointers for non-generic sign and auth operations. | 
 |     if ((OpKind == PAO_Sign || OpKind == PAO_Auth) && | 
 |         Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) { | 
 |       S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign | 
 |                                     ? diag::warn_ptrauth_sign_null_pointer | 
 |                                     : diag::warn_ptrauth_auth_null_pointer) | 
 |           << Arg->getSourceRange(); | 
 |     } | 
 |  | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Perform special checking on the arguments to ptrauth_sign_constant. | 
 |  | 
 |   // The main argument. | 
 |   if (OpKind == PAO_Sign) { | 
 |     // Require the value we're signing to have a special form. | 
 |     auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Arg); | 
 |     bool Invalid; | 
 |  | 
 |     // Must be rooted in a declaration reference. | 
 |     if (!BaseDecl) | 
 |       Invalid = true; | 
 |  | 
 |     // If it's a function declaration, we can't have an offset. | 
 |     else if (isa<FunctionDecl>(BaseDecl)) | 
 |       Invalid = !Offset.isZero(); | 
 |  | 
 |     // Otherwise we're fine. | 
 |     else | 
 |       Invalid = false; | 
 |  | 
 |     if (Invalid) | 
 |       S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer); | 
 |     return Invalid; | 
 |   } | 
 |  | 
 |   // The discriminator argument. | 
 |   assert(OpKind == PAO_Discriminator); | 
 |  | 
 |   // Must be a pointer or integer or blend thereof. | 
 |   Expr *Pointer = nullptr; | 
 |   Expr *Integer = nullptr; | 
 |   if (auto *Call = dyn_cast<CallExpr>(Arg->IgnoreParens())) { | 
 |     if (Call->getBuiltinCallee() == | 
 |         Builtin::BI__builtin_ptrauth_blend_discriminator) { | 
 |       Pointer = Call->getArg(0); | 
 |       Integer = Call->getArg(1); | 
 |     } | 
 |   } | 
 |   if (!Pointer && !Integer) { | 
 |     if (Arg->getType()->isPointerType()) | 
 |       Pointer = Arg; | 
 |     else | 
 |       Integer = Arg; | 
 |   } | 
 |  | 
 |   // Check the pointer. | 
 |   bool Invalid = false; | 
 |   if (Pointer) { | 
 |     assert(Pointer->getType()->isPointerType()); | 
 |  | 
 |     // TODO: if we're initializing a global, check that the address is | 
 |     // somehow related to what we're initializing.  This probably will | 
 |     // never really be feasible and we'll have to catch it at link-time. | 
 |     auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Pointer); | 
 |     if (!BaseDecl || !isa<VarDecl>(BaseDecl)) | 
 |       Invalid = true; | 
 |   } | 
 |  | 
 |   // Check the integer. | 
 |   if (Integer) { | 
 |     assert(Integer->getType()->isIntegerType()); | 
 |     if (!Integer->isEvaluatable(S.Context)) | 
 |       Invalid = true; | 
 |   } | 
 |  | 
 |   if (Invalid) | 
 |     S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator); | 
 |   return Invalid; | 
 | } | 
 |  | 
 | static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) { | 
 |   if (S.checkArgCount(Call, 2)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthEnabled(S, Call)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Strip) || | 
 |       checkPointerAuthKey(S, Call->getArgs()[1])) | 
 |     return ExprError(); | 
 |  | 
 |   Call->setType(Call->getArgs()[0]->getType()); | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { | 
 |   if (S.checkArgCount(Call, 2)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthEnabled(S, Call)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_BlendPointer) || | 
 |       checkPointerAuthValue(S, Call->getArgs()[1], PAO_BlendInteger)) | 
 |     return ExprError(); | 
 |  | 
 |   Call->setType(S.Context.getUIntPtrType()); | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) { | 
 |   if (S.checkArgCount(Call, 2)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthEnabled(S, Call)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_SignGeneric) || | 
 |       checkPointerAuthValue(S, Call->getArgs()[1], PAO_Discriminator)) | 
 |     return ExprError(); | 
 |  | 
 |   Call->setType(S.Context.getUIntPtrType()); | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call, | 
 |                                         PointerAuthOpKind OpKind, | 
 |                                         bool RequireConstant) { | 
 |   if (S.checkArgCount(Call, 3)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthEnabled(S, Call)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind, RequireConstant) || | 
 |       checkPointerAuthKey(S, Call->getArgs()[1]) || | 
 |       checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator, | 
 |                             RequireConstant)) | 
 |     return ExprError(); | 
 |  | 
 |   Call->setType(Call->getArgs()[0]->getType()); | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { | 
 |   if (S.checkArgCount(Call, 5)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthEnabled(S, Call)) | 
 |     return ExprError(); | 
 |   if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) || | 
 |       checkPointerAuthKey(S, Call->getArgs()[1]) || | 
 |       checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) || | 
 |       checkPointerAuthKey(S, Call->getArgs()[3]) || | 
 |       checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator)) | 
 |     return ExprError(); | 
 |  | 
 |   Call->setType(Call->getArgs()[0]->getType()); | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) { | 
 |   if (checkPointerAuthEnabled(S, Call)) | 
 |     return ExprError(); | 
 |  | 
 |   // We've already performed normal call type-checking. | 
 |   const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts(); | 
 |  | 
 |   // Operand must be an ordinary or UTF-8 string literal. | 
 |   const auto *Literal = dyn_cast<StringLiteral>(Arg); | 
 |   if (!Literal || Literal->getCharByteWidth() != 1) { | 
 |     S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal) | 
 |         << (Literal ? 1 : 0) << Arg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult GetVTablePointer(Sema &S, CallExpr *Call) { | 
 |   if (S.checkArgCount(Call, 1)) | 
 |     return ExprError(); | 
 |   Expr *FirstArg = Call->getArg(0); | 
 |   ExprResult FirstValue = S.DefaultFunctionArrayLvalueConversion(FirstArg); | 
 |   if (FirstValue.isInvalid()) | 
 |     return ExprError(); | 
 |   Call->setArg(0, FirstValue.get()); | 
 |   QualType FirstArgType = FirstArg->getType(); | 
 |   if (FirstArgType->canDecayToPointerType() && FirstArgType->isArrayType()) | 
 |     FirstArgType = S.Context.getDecayedType(FirstArgType); | 
 |  | 
 |   const CXXRecordDecl *FirstArgRecord = FirstArgType->getPointeeCXXRecordDecl(); | 
 |   if (!FirstArgRecord) { | 
 |     S.Diag(FirstArg->getBeginLoc(), diag::err_get_vtable_pointer_incorrect_type) | 
 |         << /*isPolymorphic=*/0 << FirstArgType; | 
 |     return ExprError(); | 
 |   } | 
 |   if (S.RequireCompleteType( | 
 |           FirstArg->getBeginLoc(), FirstArgType->getPointeeType(), | 
 |           diag::err_get_vtable_pointer_requires_complete_type)) { | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   if (!FirstArgRecord->isPolymorphic()) { | 
 |     S.Diag(FirstArg->getBeginLoc(), diag::err_get_vtable_pointer_incorrect_type) | 
 |         << /*isPolymorphic=*/1 << FirstArgRecord; | 
 |     return ExprError(); | 
 |   } | 
 |   QualType ReturnType = S.Context.getPointerType(S.Context.VoidTy.withConst()); | 
 |   Call->setType(ReturnType); | 
 |   return Call; | 
 | } | 
 |  | 
 | static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 1)) | 
 |     return ExprError(); | 
 |  | 
 |   // Compute __builtin_launder's parameter type from the argument. | 
 |   // The parameter type is: | 
 |   //  * The type of the argument if it's not an array or function type, | 
 |   //  Otherwise, | 
 |   //  * The decayed argument type. | 
 |   QualType ParamTy = [&]() { | 
 |     QualType ArgTy = TheCall->getArg(0)->getType(); | 
 |     if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe()) | 
 |       return S.Context.getPointerType(Ty->getElementType()); | 
 |     if (ArgTy->isFunctionType()) { | 
 |       return S.Context.getPointerType(ArgTy); | 
 |     } | 
 |     return ArgTy; | 
 |   }(); | 
 |  | 
 |   TheCall->setType(ParamTy); | 
 |  | 
 |   auto DiagSelect = [&]() -> std::optional<unsigned> { | 
 |     if (!ParamTy->isPointerType()) | 
 |       return 0; | 
 |     if (ParamTy->isFunctionPointerType()) | 
 |       return 1; | 
 |     if (ParamTy->isVoidPointerType()) | 
 |       return 2; | 
 |     return std::optional<unsigned>{}; | 
 |   }(); | 
 |   if (DiagSelect) { | 
 |     S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg) | 
 |         << *DiagSelect << TheCall->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // We either have an incomplete class type, or we have a class template | 
 |   // whose instantiation has not been forced. Example: | 
 |   // | 
 |   //   template <class T> struct Foo { T value; }; | 
 |   //   Foo<int> *p = nullptr; | 
 |   //   auto *d = __builtin_launder(p); | 
 |   if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(), | 
 |                             diag::err_incomplete_type)) | 
 |     return ExprError(); | 
 |  | 
 |   assert(ParamTy->getPointeeType()->isObjectType() && | 
 |          "Unhandled non-object pointer case"); | 
 |  | 
 |   InitializedEntity Entity = | 
 |       InitializedEntity::InitializeParameter(S.Context, ParamTy, false); | 
 |   ExprResult Arg = | 
 |       S.PerformCopyInitialization(Entity, SourceLocation(), TheCall->getArg(0)); | 
 |   if (Arg.isInvalid()) | 
 |     return ExprError(); | 
 |   TheCall->setArg(0, Arg.get()); | 
 |  | 
 |   return TheCall; | 
 | } | 
 |  | 
 | static ExprResult BuiltinIsWithinLifetime(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 1)) | 
 |     return ExprError(); | 
 |  | 
 |   ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); | 
 |   if (Arg.isInvalid()) | 
 |     return ExprError(); | 
 |   QualType ParamTy = Arg.get()->getType(); | 
 |   TheCall->setArg(0, Arg.get()); | 
 |   TheCall->setType(S.Context.BoolTy); | 
 |  | 
 |   // Only accept pointers to objects as arguments, which should have object | 
 |   // pointer or void pointer types. | 
 |   if (const auto *PT = ParamTy->getAs<PointerType>()) { | 
 |     // LWG4138: Function pointer types not allowed | 
 |     if (PT->getPointeeType()->isFunctionType()) { | 
 |       S.Diag(TheCall->getArg(0)->getExprLoc(), | 
 |              diag::err_builtin_is_within_lifetime_invalid_arg) | 
 |           << 1; | 
 |       return ExprError(); | 
 |     } | 
 |     // Disallow VLAs too since those shouldn't be able to | 
 |     // be a template parameter for `std::is_within_lifetime` | 
 |     if (PT->getPointeeType()->isVariableArrayType()) { | 
 |       S.Diag(TheCall->getArg(0)->getExprLoc(), diag::err_vla_unsupported) | 
 |           << 1 << "__builtin_is_within_lifetime"; | 
 |       return ExprError(); | 
 |     } | 
 |   } else { | 
 |     S.Diag(TheCall->getArg(0)->getExprLoc(), | 
 |            diag::err_builtin_is_within_lifetime_invalid_arg) | 
 |         << 0; | 
 |     return ExprError(); | 
 |   } | 
 |   return TheCall; | 
 | } | 
 |  | 
 | static ExprResult BuiltinTriviallyRelocate(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 3)) | 
 |     return ExprError(); | 
 |  | 
 |   QualType Dest = TheCall->getArg(0)->getType(); | 
 |   if (!Dest->isPointerType() || Dest.getCVRQualifiers() != 0) { | 
 |     S.Diag(TheCall->getArg(0)->getExprLoc(), | 
 |            diag::err_builtin_trivially_relocate_invalid_arg_type) | 
 |         << /*a pointer*/ 0; | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   QualType T = Dest->getPointeeType(); | 
 |   if (S.RequireCompleteType(TheCall->getBeginLoc(), T, | 
 |                             diag::err_incomplete_type)) | 
 |     return ExprError(); | 
 |  | 
 |   if (T.isConstQualified() || !S.IsCXXTriviallyRelocatableType(T) || | 
 |       T->isIncompleteArrayType()) { | 
 |     S.Diag(TheCall->getArg(0)->getExprLoc(), | 
 |            diag::err_builtin_trivially_relocate_invalid_arg_type) | 
 |         << (T.isConstQualified() ? /*non-const*/ 1 : /*relocatable*/ 2); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   TheCall->setType(Dest); | 
 |  | 
 |   QualType Src = TheCall->getArg(1)->getType(); | 
 |   if (Src.getCanonicalType() != Dest.getCanonicalType()) { | 
 |     S.Diag(TheCall->getArg(1)->getExprLoc(), | 
 |            diag::err_builtin_trivially_relocate_invalid_arg_type) | 
 |         << /*the same*/ 3; | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   Expr *SizeExpr = TheCall->getArg(2); | 
 |   ExprResult Size = S.DefaultLvalueConversion(SizeExpr); | 
 |   if (Size.isInvalid()) | 
 |     return ExprError(); | 
 |  | 
 |   Size = S.tryConvertExprToType(Size.get(), S.getASTContext().getSizeType()); | 
 |   if (Size.isInvalid()) | 
 |     return ExprError(); | 
 |   SizeExpr = Size.get(); | 
 |   TheCall->setArg(2, SizeExpr); | 
 |  | 
 |   return TheCall; | 
 | } | 
 |  | 
 | // Emit an error and return true if the current object format type is in the | 
 | // list of unsupported types. | 
 | static bool CheckBuiltinTargetNotInUnsupported( | 
 |     Sema &S, unsigned BuiltinID, CallExpr *TheCall, | 
 |     ArrayRef<llvm::Triple::ObjectFormatType> UnsupportedObjectFormatTypes) { | 
 |   llvm::Triple::ObjectFormatType CurObjFormat = | 
 |       S.getASTContext().getTargetInfo().getTriple().getObjectFormat(); | 
 |   if (llvm::is_contained(UnsupportedObjectFormatTypes, CurObjFormat)) { | 
 |     S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) | 
 |         << TheCall->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | // Emit an error and return true if the current architecture is not in the list | 
 | // of supported architectures. | 
 | static bool | 
 | CheckBuiltinTargetInSupported(Sema &S, CallExpr *TheCall, | 
 |                               ArrayRef<llvm::Triple::ArchType> SupportedArchs) { | 
 |   llvm::Triple::ArchType CurArch = | 
 |       S.getASTContext().getTargetInfo().getTriple().getArch(); | 
 |   if (llvm::is_contained(SupportedArchs, CurArch)) | 
 |     return false; | 
 |   S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) | 
 |       << TheCall->getSourceRange(); | 
 |   return true; | 
 | } | 
 |  | 
 | static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr, | 
 |                                  SourceLocation CallSiteLoc); | 
 |  | 
 | bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, | 
 |                                       CallExpr *TheCall) { | 
 |   switch (TI.getTriple().getArch()) { | 
 |   default: | 
 |     // Some builtins don't require additional checking, so just consider these | 
 |     // acceptable. | 
 |     return false; | 
 |   case llvm::Triple::arm: | 
 |   case llvm::Triple::armeb: | 
 |   case llvm::Triple::thumb: | 
 |   case llvm::Triple::thumbeb: | 
 |     return ARM().CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::aarch64: | 
 |   case llvm::Triple::aarch64_32: | 
 |   case llvm::Triple::aarch64_be: | 
 |     return ARM().CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::bpfeb: | 
 |   case llvm::Triple::bpfel: | 
 |     return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); | 
 |   case llvm::Triple::dxil: | 
 |     return DirectX().CheckDirectXBuiltinFunctionCall(BuiltinID, TheCall); | 
 |   case llvm::Triple::hexagon: | 
 |     return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); | 
 |   case llvm::Triple::mips: | 
 |   case llvm::Triple::mipsel: | 
 |   case llvm::Triple::mips64: | 
 |   case llvm::Triple::mips64el: | 
 |     return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::spirv: | 
 |   case llvm::Triple::spirv32: | 
 |   case llvm::Triple::spirv64: | 
 |     if (TI.getTriple().getOS() != llvm::Triple::OSType::AMDHSA) | 
 |       return SPIRV().CheckSPIRVBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |     return false; | 
 |   case llvm::Triple::systemz: | 
 |     return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); | 
 |   case llvm::Triple::x86: | 
 |   case llvm::Triple::x86_64: | 
 |     return X86().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::ppc: | 
 |   case llvm::Triple::ppcle: | 
 |   case llvm::Triple::ppc64: | 
 |   case llvm::Triple::ppc64le: | 
 |     return PPC().CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::amdgcn: | 
 |     return AMDGPU().CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall); | 
 |   case llvm::Triple::riscv32: | 
 |   case llvm::Triple::riscv64: | 
 |     return RISCV().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::loongarch32: | 
 |   case llvm::Triple::loongarch64: | 
 |     return LoongArch().CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, | 
 |                                                          TheCall); | 
 |   case llvm::Triple::wasm32: | 
 |   case llvm::Triple::wasm64: | 
 |     return Wasm().CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   case llvm::Triple::nvptx: | 
 |   case llvm::Triple::nvptx64: | 
 |     return NVPTX().CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall); | 
 |   } | 
 | } | 
 |  | 
 | // Check if \p Ty is a valid type for the elementwise math builtins. If it is | 
 | // not a valid type, emit an error message and return true. Otherwise return | 
 | // false. | 
 | static bool | 
 | checkMathBuiltinElementType(Sema &S, SourceLocation Loc, QualType ArgTy, | 
 |                             Sema::EltwiseBuiltinArgTyRestriction ArgTyRestr, | 
 |                             int ArgOrdinal) { | 
 |   QualType EltTy = ArgTy; | 
 |   if (auto *VecTy = EltTy->getAs<VectorType>()) | 
 |     EltTy = VecTy->getElementType(); | 
 |  | 
 |   switch (ArgTyRestr) { | 
 |   case Sema::EltwiseBuiltinArgTyRestriction::None: | 
 |     if (!ArgTy->getAs<VectorType>() && | 
 |         !ConstantMatrixType::isValidElementType(ArgTy)) { | 
 |       return S.Diag(Loc, diag::err_builtin_invalid_arg_type) | 
 |              << ArgOrdinal << /* vector */ 2 << /* integer */ 1 << /* fp */ 1 | 
 |              << ArgTy; | 
 |     } | 
 |     break; | 
 |   case Sema::EltwiseBuiltinArgTyRestriction::FloatTy: | 
 |     if (!EltTy->isRealFloatingType()) { | 
 |       return S.Diag(Loc, diag::err_builtin_invalid_arg_type) | 
 |              << ArgOrdinal << /* scalar or vector */ 5 << /* no int */ 0 | 
 |              << /* floating-point */ 1 << ArgTy; | 
 |     } | 
 |     break; | 
 |   case Sema::EltwiseBuiltinArgTyRestriction::IntegerTy: | 
 |     if (!EltTy->isIntegerType()) { | 
 |       return S.Diag(Loc, diag::err_builtin_invalid_arg_type) | 
 |              << ArgOrdinal << /* scalar or vector */ 5 << /* integer */ 1 | 
 |              << /* no fp */ 0 << ArgTy; | 
 |     } | 
 |     break; | 
 |   case Sema::EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy: | 
 |     if (EltTy->isUnsignedIntegerType()) { | 
 |       return S.Diag(Loc, diag::err_builtin_invalid_arg_type) | 
 |              << 1 << /* scalar or vector */ 5 << /* signed int */ 2 | 
 |              << /* or fp */ 1 << ArgTy; | 
 |     } | 
 |     break; | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | /// BuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *). | 
 | /// This checks that the target supports the builtin and that the string | 
 | /// argument is constant and valid. | 
 | static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, | 
 |                        const TargetInfo *AuxTI, unsigned BuiltinID) { | 
 |   assert((BuiltinID == Builtin::BI__builtin_cpu_supports || | 
 |           BuiltinID == Builtin::BI__builtin_cpu_is) && | 
 |          "Expecting __builtin_cpu_..."); | 
 |  | 
 |   bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports; | 
 |   const TargetInfo *TheTI = &TI; | 
 |   auto SupportsBI = [=](const TargetInfo *TInfo) { | 
 |     return TInfo && ((IsCPUSupports && TInfo->supportsCpuSupports()) || | 
 |                      (!IsCPUSupports && TInfo->supportsCpuIs())); | 
 |   }; | 
 |   if (!SupportsBI(&TI) && SupportsBI(AuxTI)) | 
 |     TheTI = AuxTI; | 
 |  | 
 |   if ((!IsCPUSupports && !TheTI->supportsCpuIs()) || | 
 |       (IsCPUSupports && !TheTI->supportsCpuSupports())) | 
 |     return S.Diag(TheCall->getBeginLoc(), | 
 |                   TI.getTriple().isOSAIX() | 
 |                       ? diag::err_builtin_aix_os_unsupported | 
 |                       : diag::err_builtin_target_unsupported) | 
 |            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); | 
 |  | 
 |   Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts(); | 
 |   // Check if the argument is a string literal. | 
 |   if (!isa<StringLiteral>(Arg)) | 
 |     return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) | 
 |            << Arg->getSourceRange(); | 
 |  | 
 |   // Check the contents of the string. | 
 |   StringRef Feature = cast<StringLiteral>(Arg)->getString(); | 
 |   if (IsCPUSupports && !TheTI->validateCpuSupports(Feature)) { | 
 |     S.Diag(TheCall->getBeginLoc(), diag::warn_invalid_cpu_supports) | 
 |         << Arg->getSourceRange(); | 
 |     return false; | 
 |   } | 
 |   if (!IsCPUSupports && !TheTI->validateCpuIs(Feature)) | 
 |     return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is) | 
 |            << Arg->getSourceRange(); | 
 |   return false; | 
 | } | 
 |  | 
 | /// Checks that __builtin_popcountg was called with a single argument, which is | 
 | /// an unsigned integer. | 
 | static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0)); | 
 |   if (ArgRes.isInvalid()) | 
 |     return true; | 
 |  | 
 |   Expr *Arg = ArgRes.get(); | 
 |   TheCall->setArg(0, Arg); | 
 |  | 
 |   QualType ArgTy = Arg->getType(); | 
 |  | 
 |   if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) { | 
 |     S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |         << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0 | 
 |         << ArgTy; | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | /// Checks that __builtin_{clzg,ctzg} was called with a first argument, which is | 
 | /// an unsigned integer, and an optional second argument, which is promoted to | 
 | /// an 'int'. | 
 | static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCountRange(TheCall, 1, 2)) | 
 |     return true; | 
 |  | 
 |   ExprResult Arg0Res = S.DefaultLvalueConversion(TheCall->getArg(0)); | 
 |   if (Arg0Res.isInvalid()) | 
 |     return true; | 
 |  | 
 |   Expr *Arg0 = Arg0Res.get(); | 
 |   TheCall->setArg(0, Arg0); | 
 |  | 
 |   QualType Arg0Ty = Arg0->getType(); | 
 |  | 
 |   if (!Arg0Ty->isUnsignedIntegerType() && !Arg0Ty->isExtVectorBoolType()) { | 
 |     S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |         << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0 | 
 |         << Arg0Ty; | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (TheCall->getNumArgs() > 1) { | 
 |     ExprResult Arg1Res = S.UsualUnaryConversions(TheCall->getArg(1)); | 
 |     if (Arg1Res.isInvalid()) | 
 |       return true; | 
 |  | 
 |     Expr *Arg1 = Arg1Res.get(); | 
 |     TheCall->setArg(1, Arg1); | 
 |  | 
 |     QualType Arg1Ty = Arg1->getType(); | 
 |  | 
 |     if (!Arg1Ty->isSpecificBuiltinType(BuiltinType::Int)) { | 
 |       S.Diag(Arg1->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |           << 2 << /* scalar */ 1 << /* 'int' ty */ 4 << /* no fp */ 0 << Arg1Ty; | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, | 
 |                                    unsigned Pos, bool AllowConst, | 
 |                                    bool AllowAS) { | 
 |   QualType MaskTy = MaskArg->getType(); | 
 |   if (!MaskTy->isExtVectorBoolType()) | 
 |     return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |            << 1 << /* vector of */ 4 << /* booleans */ 6 << /* no fp */ 0 | 
 |            << MaskTy; | 
 |  | 
 |   QualType PtrTy = PtrArg->getType(); | 
 |   if (!PtrTy->isPointerType() || PtrTy->getPointeeType()->isVectorType()) | 
 |     return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) | 
 |            << Pos << "scalar pointer"; | 
 |  | 
 |   QualType PointeeTy = PtrTy->getPointeeType(); | 
 |   if (PointeeTy.isVolatileQualified() || PointeeTy->isAtomicType() || | 
 |       (!AllowConst && PointeeTy.isConstQualified()) || | 
 |       (!AllowAS && PointeeTy.hasAddressSpace())) { | 
 |     QualType Target = | 
 |         S.Context.getPointerType(PointeeTy.getAtomicUnqualifiedType()); | 
 |     return S.Diag(PtrArg->getExprLoc(), | 
 |                   diag::err_typecheck_convert_incompatible) | 
 |            << PtrTy << Target << /*different qualifiers=*/5 | 
 |            << /*qualifier difference=*/0 << /*parameter mismatch=*/3 << 2 | 
 |            << PtrTy << Target; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | static bool ConvertMaskedBuiltinArgs(Sema &S, CallExpr *TheCall) { | 
 |   bool TypeDependent = false; | 
 |   for (unsigned Arg = 0, E = TheCall->getNumArgs(); Arg != E; ++Arg) { | 
 |     ExprResult Converted = | 
 |         S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(Arg)); | 
 |     if (Converted.isInvalid()) | 
 |       return true; | 
 |     TheCall->setArg(Arg, Converted.get()); | 
 |     TypeDependent |= Converted.get()->isTypeDependent(); | 
 |   } | 
 |  | 
 |   if (TypeDependent) | 
 |     TheCall->setType(S.Context.DependentTy); | 
 |   return false; | 
 | } | 
 |  | 
 | static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCountRange(TheCall, 2, 3)) | 
 |     return ExprError(); | 
 |  | 
 |   if (ConvertMaskedBuiltinArgs(S, TheCall)) | 
 |     return ExprError(); | 
 |  | 
 |   Expr *MaskArg = TheCall->getArg(0); | 
 |   Expr *PtrArg = TheCall->getArg(1); | 
 |   if (TheCall->isTypeDependent()) | 
 |     return TheCall; | 
 |  | 
 |   if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 2, /*AllowConst=*/true, | 
 |                              TheCall->getBuiltinCallee() == | 
 |                                  Builtin::BI__builtin_masked_load)) | 
 |     return ExprError(); | 
 |  | 
 |   QualType MaskTy = MaskArg->getType(); | 
 |   QualType PtrTy = PtrArg->getType(); | 
 |   QualType PointeeTy = PtrTy->getPointeeType(); | 
 |   const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); | 
 |  | 
 |   QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), | 
 |                                               MaskVecTy->getNumElements()); | 
 |   if (TheCall->getNumArgs() == 3) { | 
 |     Expr *PassThruArg = TheCall->getArg(2); | 
 |     QualType PassThruTy = PassThruArg->getType(); | 
 |     if (!S.Context.hasSameType(PassThruTy, RetTy)) | 
 |       return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) | 
 |              << /* third argument */ 3 << RetTy; | 
 |   } | 
 |  | 
 |   TheCall->setType(RetTy); | 
 |   return TheCall; | 
 | } | 
 |  | 
 | static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 3)) | 
 |     return ExprError(); | 
 |  | 
 |   if (ConvertMaskedBuiltinArgs(S, TheCall)) | 
 |     return ExprError(); | 
 |  | 
 |   Expr *MaskArg = TheCall->getArg(0); | 
 |   Expr *ValArg = TheCall->getArg(1); | 
 |   Expr *PtrArg = TheCall->getArg(2); | 
 |   if (TheCall->isTypeDependent()) | 
 |     return TheCall; | 
 |  | 
 |   if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false, | 
 |                              TheCall->getBuiltinCallee() == | 
 |                                  Builtin::BI__builtin_masked_store)) | 
 |     return ExprError(); | 
 |  | 
 |   QualType MaskTy = MaskArg->getType(); | 
 |   QualType PtrTy = PtrArg->getType(); | 
 |   QualType ValTy = ValArg->getType(); | 
 |   if (!ValTy->isVectorType()) | 
 |     return ExprError( | 
 |         S.Diag(ValArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) | 
 |         << 2 << "vector"); | 
 |  | 
 |   QualType PointeeTy = PtrTy->getPointeeType(); | 
 |   const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); | 
 |   QualType MemoryTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), | 
 |                                                  MaskVecTy->getNumElements()); | 
 |   if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), | 
 |                              MemoryTy.getUnqualifiedType())) | 
 |     return ExprError(S.Diag(TheCall->getBeginLoc(), | 
 |                             diag::err_vec_builtin_incompatible_vector) | 
 |                      << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ 2 | 
 |                      << SourceRange(TheCall->getArg(1)->getBeginLoc(), | 
 |                                     TheCall->getArg(1)->getEndLoc())); | 
 |  | 
 |   TheCall->setType(S.Context.VoidTy); | 
 |   return TheCall; | 
 | } | 
 |  | 
 | static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCountRange(TheCall, 3, 4)) | 
 |     return ExprError(); | 
 |  | 
 |   if (ConvertMaskedBuiltinArgs(S, TheCall)) | 
 |     return ExprError(); | 
 |  | 
 |   Expr *MaskArg = TheCall->getArg(0); | 
 |   Expr *IdxArg = TheCall->getArg(1); | 
 |   Expr *PtrArg = TheCall->getArg(2); | 
 |   if (TheCall->isTypeDependent()) | 
 |     return TheCall; | 
 |  | 
 |   if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/true, | 
 |                              /*AllowAS=*/true)) | 
 |     return ExprError(); | 
 |  | 
 |   QualType IdxTy = IdxArg->getType(); | 
 |   const VectorType *IdxVecTy = IdxTy->getAs<VectorType>(); | 
 |   if (!IdxTy->isExtVectorType() || !IdxVecTy->getElementType()->isIntegerType()) | 
 |     return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |            << 1 << /* vector of */ 4 << /* integer */ 1 << /* no fp */ 0 | 
 |            << IdxTy; | 
 |  | 
 |   QualType MaskTy = MaskArg->getType(); | 
 |   QualType PtrTy = PtrArg->getType(); | 
 |   QualType PointeeTy = PtrTy->getPointeeType(); | 
 |   const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); | 
 |   if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements()) | 
 |     return ExprError( | 
 |         S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) | 
 |         << S.getASTContext().BuiltinInfo.getQuotedName( | 
 |                TheCall->getBuiltinCallee()) | 
 |         << MaskTy << IdxTy); | 
 |  | 
 |   QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), | 
 |                                               MaskVecTy->getNumElements()); | 
 |   if (TheCall->getNumArgs() == 4) { | 
 |     Expr *PassThruArg = TheCall->getArg(3); | 
 |     QualType PassThruTy = PassThruArg->getType(); | 
 |     if (!S.Context.hasSameType(PassThruTy, RetTy)) | 
 |       return S.Diag(PassThruArg->getExprLoc(), | 
 |                     diag::err_vec_masked_load_store_ptr) | 
 |              << /* fourth argument */ 4 << RetTy; | 
 |   } | 
 |  | 
 |   TheCall->setType(RetTy); | 
 |   return TheCall; | 
 | } | 
 |  | 
 | static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { | 
 |   if (S.checkArgCount(TheCall, 4)) | 
 |     return ExprError(); | 
 |  | 
 |   if (ConvertMaskedBuiltinArgs(S, TheCall)) | 
 |     return ExprError(); | 
 |  | 
 |   Expr *MaskArg = TheCall->getArg(0); | 
 |   Expr *IdxArg = TheCall->getArg(1); | 
 |   Expr *ValArg = TheCall->getArg(2); | 
 |   Expr *PtrArg = TheCall->getArg(3); | 
 |   if (TheCall->isTypeDependent()) | 
 |     return TheCall; | 
 |  | 
 |   if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 4, /*AllowConst=*/false, | 
 |                              /*AllowAS=*/true)) | 
 |     return ExprError(); | 
 |  | 
 |   QualType IdxTy = IdxArg->getType(); | 
 |   const VectorType *IdxVecTy = IdxTy->getAs<VectorType>(); | 
 |   if (!IdxTy->isExtVectorType() || !IdxVecTy->getElementType()->isIntegerType()) | 
 |     return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |            << 2 << /* vector of */ 4 << /* integer */ 1 << /* no fp */ 0 | 
 |            << IdxTy; | 
 |  | 
 |   QualType ValTy = ValArg->getType(); | 
 |   QualType MaskTy = MaskArg->getType(); | 
 |   QualType PtrTy = PtrArg->getType(); | 
 |   QualType PointeeTy = PtrTy->getPointeeType(); | 
 |  | 
 |   const VectorType *MaskVecTy = MaskTy->castAs<VectorType>(); | 
 |   const VectorType *ValVecTy = ValTy->castAs<VectorType>(); | 
 |   if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements()) | 
 |     return ExprError( | 
 |         S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) | 
 |         << S.getASTContext().BuiltinInfo.getQuotedName( | 
 |                TheCall->getBuiltinCallee()) | 
 |         << MaskTy << IdxTy); | 
 |   if (MaskVecTy->getNumElements() != ValVecTy->getNumElements()) | 
 |     return ExprError( | 
 |         S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) | 
 |         << S.getASTContext().BuiltinInfo.getQuotedName( | 
 |                TheCall->getBuiltinCallee()) | 
 |         << MaskTy << ValTy); | 
 |  | 
 |   QualType ArgTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), | 
 |                                               MaskVecTy->getNumElements()); | 
 |   if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), ArgTy)) | 
 |     return ExprError(S.Diag(TheCall->getBeginLoc(), | 
 |                             diag::err_vec_builtin_incompatible_vector) | 
 |                      << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ 2 | 
 |                      << SourceRange(TheCall->getArg(1)->getBeginLoc(), | 
 |                                     TheCall->getArg(1)->getEndLoc())); | 
 |  | 
 |   TheCall->setType(S.Context.VoidTy); | 
 |   return TheCall; | 
 | } | 
 |  | 
 | static ExprResult BuiltinInvoke(Sema &S, CallExpr *TheCall) { | 
 |   SourceLocation Loc = TheCall->getBeginLoc(); | 
 |   MutableArrayRef Args(TheCall->getArgs(), TheCall->getNumArgs()); | 
 |   assert(llvm::none_of(Args, [](Expr *Arg) { return Arg->isTypeDependent(); })); | 
 |  | 
 |   if (Args.size() == 0) { | 
 |     S.Diag(TheCall->getBeginLoc(), | 
 |            diag::err_typecheck_call_too_few_args_at_least) | 
 |         << /*callee_type=*/0 << /*min_arg_count=*/1 << /*actual_arg_count=*/0 | 
 |         << /*is_non_object=*/0 << TheCall->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   QualType FuncT = Args[0]->getType(); | 
 |  | 
 |   if (const auto *MPT = FuncT->getAs<MemberPointerType>()) { | 
 |     if (Args.size() < 2) { | 
 |       S.Diag(TheCall->getBeginLoc(), | 
 |              diag::err_typecheck_call_too_few_args_at_least) | 
 |           << /*callee_type=*/0 << /*min_arg_count=*/2 << /*actual_arg_count=*/1 | 
 |           << /*is_non_object=*/0 << TheCall->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |  | 
 |     const Type *MemPtrClass = MPT->getQualifier().getAsType(); | 
 |     QualType ObjectT = Args[1]->getType(); | 
 |  | 
 |     if (MPT->isMemberDataPointer() && S.checkArgCount(TheCall, 2)) | 
 |       return ExprError(); | 
 |  | 
 |     ExprResult ObjectArg = [&]() -> ExprResult { | 
 |       // (1.1): (t1.*f)(t2, ..., tN) when f is a pointer to a member function of | 
 |       // a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> || | 
 |       // is_base_of_v<T, remove_cvref_t<decltype(t1)>> is true; | 
 |       // (1.4): t1.*f when N=1 and f is a pointer to data member of a class T | 
 |       // and is_same_v<T, remove_cvref_t<decltype(t1)>> || | 
 |       // is_base_of_v<T, remove_cvref_t<decltype(t1)>> is true; | 
 |       if (S.Context.hasSameType(QualType(MemPtrClass, 0), | 
 |                                 S.BuiltinRemoveCVRef(ObjectT, Loc)) || | 
 |           S.BuiltinIsBaseOf(Args[1]->getBeginLoc(), QualType(MemPtrClass, 0), | 
 |                             S.BuiltinRemoveCVRef(ObjectT, Loc))) { | 
 |         return Args[1]; | 
 |       } | 
 |  | 
 |       // (t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of | 
 |       // a class T and remove_cvref_t<decltype(t1)> is a specialization of | 
 |       // reference_wrapper; | 
 |       if (const auto *RD = ObjectT->getAsCXXRecordDecl()) { | 
 |         if (RD->isInStdNamespace() && | 
 |             RD->getDeclName().getAsString() == "reference_wrapper") { | 
 |           CXXScopeSpec SS; | 
 |           IdentifierInfo *GetName = &S.Context.Idents.get("get"); | 
 |           UnqualifiedId GetID; | 
 |           GetID.setIdentifier(GetName, Loc); | 
 |  | 
 |           ExprResult MemExpr = S.ActOnMemberAccessExpr( | 
 |               S.getCurScope(), Args[1], Loc, tok::period, SS, | 
 |               /*TemplateKWLoc=*/SourceLocation(), GetID, nullptr); | 
 |  | 
 |           if (MemExpr.isInvalid()) | 
 |             return ExprError(); | 
 |  | 
 |           return S.ActOnCallExpr(S.getCurScope(), MemExpr.get(), Loc, {}, Loc); | 
 |         } | 
 |       } | 
 |  | 
 |       // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a | 
 |       // class T and t1 does not satisfy the previous two items; | 
 |  | 
 |       return S.ActOnUnaryOp(S.getCurScope(), Loc, tok::star, Args[1]); | 
 |     }(); | 
 |  | 
 |     if (ObjectArg.isInvalid()) | 
 |       return ExprError(); | 
 |  | 
 |     ExprResult BinOp = S.ActOnBinOp(S.getCurScope(), TheCall->getBeginLoc(), | 
 |                                     tok::periodstar, ObjectArg.get(), Args[0]); | 
 |     if (BinOp.isInvalid()) | 
 |       return ExprError(); | 
 |  | 
 |     if (MPT->isMemberDataPointer()) | 
 |       return BinOp; | 
 |  | 
 |     auto *MemCall = new (S.Context) | 
 |         ParenExpr(SourceLocation(), SourceLocation(), BinOp.get()); | 
 |  | 
 |     return S.ActOnCallExpr(S.getCurScope(), MemCall, TheCall->getBeginLoc(), | 
 |                            Args.drop_front(2), TheCall->getRParenLoc()); | 
 |   } | 
 |   return S.ActOnCallExpr(S.getCurScope(), Args.front(), TheCall->getBeginLoc(), | 
 |                          Args.drop_front(), TheCall->getRParenLoc()); | 
 | } | 
 |  | 
 | ExprResult | 
 | Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, | 
 |                                CallExpr *TheCall) { | 
 |   ExprResult TheCallResult(TheCall); | 
 |  | 
 |   // Find out if any arguments are required to be integer constant expressions. | 
 |   unsigned ICEArguments = 0; | 
 |   ASTContext::GetBuiltinTypeError Error; | 
 |   Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); | 
 |   if (Error != ASTContext::GE_None) | 
 |     ICEArguments = 0;  // Don't diagnose previously diagnosed errors. | 
 |  | 
 |   // If any arguments are required to be ICE's, check and diagnose. | 
 |   for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { | 
 |     // Skip arguments not required to be ICE's. | 
 |     if ((ICEArguments & (1 << ArgNo)) == 0) continue; | 
 |  | 
 |     llvm::APSInt Result; | 
 |     // If we don't have enough arguments, continue so we can issue better | 
 |     // diagnostic in checkArgCount(...) | 
 |     if (ArgNo < TheCall->getNumArgs() && | 
 |         BuiltinConstantArg(TheCall, ArgNo, Result)) | 
 |       return true; | 
 |     ICEArguments &= ~(1 << ArgNo); | 
 |   } | 
 |  | 
 |   FPOptions FPO; | 
 |   switch (BuiltinID) { | 
 |   case Builtin::BI__builtin_cpu_supports: | 
 |   case Builtin::BI__builtin_cpu_is: | 
 |     if (BuiltinCpu(*this, Context.getTargetInfo(), TheCall, | 
 |                    Context.getAuxTargetInfo(), BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_cpu_init: | 
 |     if (!Context.getTargetInfo().supportsCpuInit()) { | 
 |       Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) | 
 |           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); | 
 |       return ExprError(); | 
 |     } | 
 |     break; | 
 |   case Builtin::BI__builtin___CFStringMakeConstantString: | 
 |     // CFStringMakeConstantString is currently not implemented for GOFF (i.e., | 
 |     // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported | 
 |     if (CheckBuiltinTargetNotInUnsupported( | 
 |             *this, BuiltinID, TheCall, | 
 |             {llvm::Triple::GOFF, llvm::Triple::XCOFF})) | 
 |       return ExprError(); | 
 |     assert(TheCall->getNumArgs() == 1 && | 
 |            "Wrong # arguments to builtin CFStringMakeConstantString"); | 
 |     if (ObjC().CheckObjCString(TheCall->getArg(0))) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_ms_va_start: | 
 |   case Builtin::BI__builtin_stdarg_start: | 
 |   case Builtin::BI__builtin_va_start: | 
 |   case Builtin::BI__builtin_c23_va_start: | 
 |     if (BuiltinVAStart(BuiltinID, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__va_start: { | 
 |     switch (Context.getTargetInfo().getTriple().getArch()) { | 
 |     case llvm::Triple::aarch64: | 
 |     case llvm::Triple::arm: | 
 |     case llvm::Triple::thumb: | 
 |       if (BuiltinVAStartARMMicrosoft(TheCall)) | 
 |         return ExprError(); | 
 |       break; | 
 |     default: | 
 |       if (BuiltinVAStart(BuiltinID, TheCall)) | 
 |         return ExprError(); | 
 |       break; | 
 |     } | 
 |     break; | 
 |   } | 
 |  | 
 |   // The acquire, release, and no fence variants are ARM and AArch64 only. | 
 |   case Builtin::BI_interlockedbittestandset_acq: | 
 |   case Builtin::BI_interlockedbittestandset_rel: | 
 |   case Builtin::BI_interlockedbittestandset_nf: | 
 |   case Builtin::BI_interlockedbittestandreset_acq: | 
 |   case Builtin::BI_interlockedbittestandreset_rel: | 
 |   case Builtin::BI_interlockedbittestandreset_nf: | 
 |     if (CheckBuiltinTargetInSupported( | 
 |             *this, TheCall, | 
 |             {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   // The 64-bit bittest variants are x64, ARM, and AArch64 only. | 
 |   case Builtin::BI_bittest64: | 
 |   case Builtin::BI_bittestandcomplement64: | 
 |   case Builtin::BI_bittestandreset64: | 
 |   case Builtin::BI_bittestandset64: | 
 |   case Builtin::BI_interlockedbittestandreset64: | 
 |   case Builtin::BI_interlockedbittestandset64: | 
 |     if (CheckBuiltinTargetInSupported( | 
 |             *this, TheCall, | 
 |             {llvm::Triple::x86_64, llvm::Triple::arm, llvm::Triple::thumb, | 
 |              llvm::Triple::aarch64, llvm::Triple::amdgcn})) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   // The 64-bit acquire, release, and no fence variants are AArch64 only. | 
 |   case Builtin::BI_interlockedbittestandreset64_acq: | 
 |   case Builtin::BI_interlockedbittestandreset64_rel: | 
 |   case Builtin::BI_interlockedbittestandreset64_nf: | 
 |   case Builtin::BI_interlockedbittestandset64_acq: | 
 |   case Builtin::BI_interlockedbittestandset64_rel: | 
 |   case Builtin::BI_interlockedbittestandset64_nf: | 
 |     if (CheckBuiltinTargetInSupported(*this, TheCall, {llvm::Triple::aarch64})) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   case Builtin::BI__builtin_set_flt_rounds: | 
 |     if (CheckBuiltinTargetInSupported( | 
 |             *this, TheCall, | 
 |             {llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::arm, | 
 |              llvm::Triple::thumb, llvm::Triple::aarch64, llvm::Triple::amdgcn, | 
 |              llvm::Triple::ppc, llvm::Triple::ppc64, llvm::Triple::ppcle, | 
 |              llvm::Triple::ppc64le})) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   case Builtin::BI__builtin_isgreater: | 
 |   case Builtin::BI__builtin_isgreaterequal: | 
 |   case Builtin::BI__builtin_isless: | 
 |   case Builtin::BI__builtin_islessequal: | 
 |   case Builtin::BI__builtin_islessgreater: | 
 |   case Builtin::BI__builtin_isunordered: | 
 |     if (BuiltinUnorderedCompare(TheCall, BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_fpclassify: | 
 |     if (BuiltinFPClassification(TheCall, 6, BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_isfpclass: | 
 |     if (BuiltinFPClassification(TheCall, 2, BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_isfinite: | 
 |   case Builtin::BI__builtin_isinf: | 
 |   case Builtin::BI__builtin_isinf_sign: | 
 |   case Builtin::BI__builtin_isnan: | 
 |   case Builtin::BI__builtin_issignaling: | 
 |   case Builtin::BI__builtin_isnormal: | 
 |   case Builtin::BI__builtin_issubnormal: | 
 |   case Builtin::BI__builtin_iszero: | 
 |   case Builtin::BI__builtin_signbit: | 
 |   case Builtin::BI__builtin_signbitf: | 
 |   case Builtin::BI__builtin_signbitl: | 
 |     if (BuiltinFPClassification(TheCall, 1, BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_shufflevector: | 
 |     return BuiltinShuffleVector(TheCall); | 
 |     // TheCall will be freed by the smart pointer here, but that's fine, since | 
 |     // BuiltinShuffleVector guts it, but then doesn't release it. | 
 |   case Builtin::BI__builtin_masked_load: | 
 |   case Builtin::BI__builtin_masked_expand_load: | 
 |     return BuiltinMaskedLoad(*this, TheCall); | 
 |   case Builtin::BI__builtin_masked_store: | 
 |   case Builtin::BI__builtin_masked_compress_store: | 
 |     return BuiltinMaskedStore(*this, TheCall); | 
 |   case Builtin::BI__builtin_masked_gather: | 
 |     return BuiltinMaskedGather(*this, TheCall); | 
 |   case Builtin::BI__builtin_masked_scatter: | 
 |     return BuiltinMaskedScatter(*this, TheCall); | 
 |   case Builtin::BI__builtin_invoke: | 
 |     return BuiltinInvoke(*this, TheCall); | 
 |   case Builtin::BI__builtin_prefetch: | 
 |     if (BuiltinPrefetch(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_alloca_with_align: | 
 |   case Builtin::BI__builtin_alloca_with_align_uninitialized: | 
 |     if (BuiltinAllocaWithAlign(TheCall)) | 
 |       return ExprError(); | 
 |     [[fallthrough]]; | 
 |   case Builtin::BI__builtin_alloca: | 
 |   case Builtin::BI__builtin_alloca_uninitialized: | 
 |     Diag(TheCall->getBeginLoc(), diag::warn_alloca) | 
 |         << TheCall->getDirectCallee(); | 
 |     if (getLangOpts().OpenCL) { | 
 |       builtinAllocaAddrSpace(*this, TheCall); | 
 |     } | 
 |     break; | 
 |   case Builtin::BI__arithmetic_fence: | 
 |     if (BuiltinArithmeticFence(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__assume: | 
 |   case Builtin::BI__builtin_assume: | 
 |     if (BuiltinAssume(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_assume_aligned: | 
 |     if (BuiltinAssumeAligned(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_dynamic_object_size: | 
 |   case Builtin::BI__builtin_object_size: | 
 |     if (BuiltinConstantArgRange(TheCall, 1, 0, 3)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_longjmp: | 
 |     if (BuiltinLongjmp(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_setjmp: | 
 |     if (BuiltinSetjmp(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_classify_type: | 
 |     if (checkArgCount(TheCall, 1)) | 
 |       return true; | 
 |     TheCall->setType(Context.IntTy); | 
 |     break; | 
 |   case Builtin::BI__builtin_complex: | 
 |     if (BuiltinComplex(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_constant_p: { | 
 |     if (checkArgCount(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 BuiltinLaunder(*this, TheCall); | 
 |   case Builtin::BI__builtin_is_within_lifetime: | 
 |     return BuiltinIsWithinLifetime(*this, TheCall); | 
 |   case Builtin::BI__builtin_trivially_relocate: | 
 |     return BuiltinTriviallyRelocate(*this, TheCall); | 
 |  | 
 |   case Builtin::BI__sync_fetch_and_add: | 
 |   case Builtin::BI__sync_fetch_and_add_1: | 
 |   case Builtin::BI__sync_fetch_and_add_2: | 
 |   case Builtin::BI__sync_fetch_and_add_4: | 
 |   case Builtin::BI__sync_fetch_and_add_8: | 
 |   case Builtin::BI__sync_fetch_and_add_16: | 
 |   case Builtin::BI__sync_fetch_and_sub: | 
 |   case Builtin::BI__sync_fetch_and_sub_1: | 
 |   case Builtin::BI__sync_fetch_and_sub_2: | 
 |   case Builtin::BI__sync_fetch_and_sub_4: | 
 |   case Builtin::BI__sync_fetch_and_sub_8: | 
 |   case Builtin::BI__sync_fetch_and_sub_16: | 
 |   case Builtin::BI__sync_fetch_and_or: | 
 |   case Builtin::BI__sync_fetch_and_or_1: | 
 |   case Builtin::BI__sync_fetch_and_or_2: | 
 |   case Builtin::BI__sync_fetch_and_or_4: | 
 |   case Builtin::BI__sync_fetch_and_or_8: | 
 |   case Builtin::BI__sync_fetch_and_or_16: | 
 |   case Builtin::BI__sync_fetch_and_and: | 
 |   case Builtin::BI__sync_fetch_and_and_1: | 
 |   case Builtin::BI__sync_fetch_and_and_2: | 
 |   case Builtin::BI__sync_fetch_and_and_4: | 
 |   case Builtin::BI__sync_fetch_and_and_8: | 
 |   case Builtin::BI__sync_fetch_and_and_16: | 
 |   case Builtin::BI__sync_fetch_and_xor: | 
 |   case Builtin::BI__sync_fetch_and_xor_1: | 
 |   case Builtin::BI__sync_fetch_and_xor_2: | 
 |   case Builtin::BI__sync_fetch_and_xor_4: | 
 |   case Builtin::BI__sync_fetch_and_xor_8: | 
 |   case Builtin::BI__sync_fetch_and_xor_16: | 
 |   case Builtin::BI__sync_fetch_and_nand: | 
 |   case Builtin::BI__sync_fetch_and_nand_1: | 
 |   case Builtin::BI__sync_fetch_and_nand_2: | 
 |   case Builtin::BI__sync_fetch_and_nand_4: | 
 |   case Builtin::BI__sync_fetch_and_nand_8: | 
 |   case Builtin::BI__sync_fetch_and_nand_16: | 
 |   case Builtin::BI__sync_add_and_fetch: | 
 |   case Builtin::BI__sync_add_and_fetch_1: | 
 |   case Builtin::BI__sync_add_and_fetch_2: | 
 |   case Builtin::BI__sync_add_and_fetch_4: | 
 |   case Builtin::BI__sync_add_and_fetch_8: | 
 |   case Builtin::BI__sync_add_and_fetch_16: | 
 |   case Builtin::BI__sync_sub_and_fetch: | 
 |   case Builtin::BI__sync_sub_and_fetch_1: | 
 |   case Builtin::BI__sync_sub_and_fetch_2: | 
 |   case Builtin::BI__sync_sub_and_fetch_4: | 
 |   case Builtin::BI__sync_sub_and_fetch_8: | 
 |   case Builtin::BI__sync_sub_and_fetch_16: | 
 |   case Builtin::BI__sync_and_and_fetch: | 
 |   case Builtin::BI__sync_and_and_fetch_1: | 
 |   case Builtin::BI__sync_and_and_fetch_2: | 
 |   case Builtin::BI__sync_and_and_fetch_4: | 
 |   case Builtin::BI__sync_and_and_fetch_8: | 
 |   case Builtin::BI__sync_and_and_fetch_16: | 
 |   case Builtin::BI__sync_or_and_fetch: | 
 |   case Builtin::BI__sync_or_and_fetch_1: | 
 |   case Builtin::BI__sync_or_and_fetch_2: | 
 |   case Builtin::BI__sync_or_and_fetch_4: | 
 |   case Builtin::BI__sync_or_and_fetch_8: | 
 |   case Builtin::BI__sync_or_and_fetch_16: | 
 |   case Builtin::BI__sync_xor_and_fetch: | 
 |   case Builtin::BI__sync_xor_and_fetch_1: | 
 |   case Builtin::BI__sync_xor_and_fetch_2: | 
 |   case Builtin::BI__sync_xor_and_fetch_4: | 
 |   case Builtin::BI__sync_xor_and_fetch_8: | 
 |   case Builtin::BI__sync_xor_and_fetch_16: | 
 |   case Builtin::BI__sync_nand_and_fetch: | 
 |   case Builtin::BI__sync_nand_and_fetch_1: | 
 |   case Builtin::BI__sync_nand_and_fetch_2: | 
 |   case Builtin::BI__sync_nand_and_fetch_4: | 
 |   case Builtin::BI__sync_nand_and_fetch_8: | 
 |   case Builtin::BI__sync_nand_and_fetch_16: | 
 |   case Builtin::BI__sync_val_compare_and_swap: | 
 |   case Builtin::BI__sync_val_compare_and_swap_1: | 
 |   case Builtin::BI__sync_val_compare_and_swap_2: | 
 |   case Builtin::BI__sync_val_compare_and_swap_4: | 
 |   case Builtin::BI__sync_val_compare_and_swap_8: | 
 |   case Builtin::BI__sync_val_compare_and_swap_16: | 
 |   case Builtin::BI__sync_bool_compare_and_swap: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_1: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_2: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_4: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_8: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_16: | 
 |   case Builtin::BI__sync_lock_test_and_set: | 
 |   case Builtin::BI__sync_lock_test_and_set_1: | 
 |   case Builtin::BI__sync_lock_test_and_set_2: | 
 |   case Builtin::BI__sync_lock_test_and_set_4: | 
 |   case Builtin::BI__sync_lock_test_and_set_8: | 
 |   case Builtin::BI__sync_lock_test_and_set_16: | 
 |   case Builtin::BI__sync_lock_release: | 
 |   case Builtin::BI__sync_lock_release_1: | 
 |   case Builtin::BI__sync_lock_release_2: | 
 |   case Builtin::BI__sync_lock_release_4: | 
 |   case Builtin::BI__sync_lock_release_8: | 
 |   case Builtin::BI__sync_lock_release_16: | 
 |   case Builtin::BI__sync_swap: | 
 |   case Builtin::BI__sync_swap_1: | 
 |   case Builtin::BI__sync_swap_2: | 
 |   case Builtin::BI__sync_swap_4: | 
 |   case Builtin::BI__sync_swap_8: | 
 |   case Builtin::BI__sync_swap_16: | 
 |     return BuiltinAtomicOverloaded(TheCallResult); | 
 |   case Builtin::BI__sync_synchronize: | 
 |     Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst) | 
 |         << TheCall->getCallee()->getSourceRange(); | 
 |     break; | 
 |   case Builtin::BI__builtin_nontemporal_load: | 
 |   case Builtin::BI__builtin_nontemporal_store: | 
 |     return BuiltinNontemporalOverloaded(TheCallResult); | 
 |   case Builtin::BI__builtin_memcpy_inline: { | 
 |     clang::Expr *SizeOp = TheCall->getArg(2); | 
 |     // We warn about copying to or from `nullptr` pointers when `size` is | 
 |     // greater than 0. When `size` is value dependent we cannot evaluate its | 
 |     // value so we bail out. | 
 |     if (SizeOp->isValueDependent()) | 
 |       break; | 
 |     if (!SizeOp->EvaluateKnownConstInt(Context).isZero()) { | 
 |       CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc()); | 
 |       CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc()); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_memset_inline: { | 
 |     clang::Expr *SizeOp = TheCall->getArg(2); | 
 |     // We warn about filling to `nullptr` pointers when `size` is greater than | 
 |     // 0. When `size` is value dependent we cannot evaluate its value so we bail | 
 |     // out. | 
 |     if (SizeOp->isValueDependent()) | 
 |       break; | 
 |     if (!SizeOp->EvaluateKnownConstInt(Context).isZero()) | 
 |       CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc()); | 
 |     break; | 
 |   } | 
 | #define ATOMIC_BUILTIN(ID, TYPE, ATTRS)                                        \ | 
 |   case Builtin::BI##ID:                                                        \ | 
 |     return AtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); | 
 | #include "clang/Basic/Builtins.inc" | 
 |   case Builtin::BI__annotation: | 
 |     if (BuiltinMSVCAnnotation(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_annotation: | 
 |     if (BuiltinAnnotation(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_addressof: | 
 |     if (BuiltinAddressof(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_function_start: | 
 |     if (BuiltinFunctionStart(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_is_aligned: | 
 |   case Builtin::BI__builtin_align_up: | 
 |   case Builtin::BI__builtin_align_down: | 
 |     if (BuiltinAlignment(*this, TheCall, BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_add_overflow: | 
 |   case Builtin::BI__builtin_sub_overflow: | 
 |   case Builtin::BI__builtin_mul_overflow: | 
 |     if (BuiltinOverflow(*this, TheCall, BuiltinID)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_operator_new: | 
 |   case Builtin::BI__builtin_operator_delete: { | 
 |     bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; | 
 |     ExprResult Res = | 
 |         BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); | 
 |     return Res; | 
 |   } | 
 |   case Builtin::BI__builtin_dump_struct: | 
 |     return BuiltinDumpStruct(*this, TheCall); | 
 |   case Builtin::BI__builtin_expect_with_probability: { | 
 |     // We first want to ensure we are called with 3 arguments | 
 |     if (checkArgCount(TheCall, 3)) | 
 |       return ExprError(); | 
 |     // then check probability is constant float in range [0.0, 1.0] | 
 |     const Expr *ProbArg = TheCall->getArg(2); | 
 |     SmallVector<PartialDiagnosticAt, 8> Notes; | 
 |     Expr::EvalResult Eval; | 
 |     Eval.Diag = &Notes; | 
 |     if ((!ProbArg->EvaluateAsConstantExpr(Eval, Context)) || | 
 |         !Eval.Val.isFloat()) { | 
 |       Diag(ProbArg->getBeginLoc(), diag::err_probability_not_constant_float) | 
 |           << ProbArg->getSourceRange(); | 
 |       for (const PartialDiagnosticAt &PDiag : Notes) | 
 |         Diag(PDiag.first, PDiag.second); | 
 |       return ExprError(); | 
 |     } | 
 |     llvm::APFloat Probability = Eval.Val.getFloat(); | 
 |     bool LoseInfo = false; | 
 |     Probability.convert(llvm::APFloat::IEEEdouble(), | 
 |                         llvm::RoundingMode::Dynamic, &LoseInfo); | 
 |     if (!(Probability >= llvm::APFloat(0.0) && | 
 |           Probability <= llvm::APFloat(1.0))) { | 
 |       Diag(ProbArg->getBeginLoc(), diag::err_probability_out_of_range) | 
 |           << ProbArg->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_preserve_access_index: | 
 |     if (BuiltinPreserveAI(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_call_with_static_chain: | 
 |     if (BuiltinCallWithStaticChain(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__exception_code: | 
 |   case Builtin::BI_exception_code: | 
 |     if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, | 
 |                              diag::err_seh___except_block)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__exception_info: | 
 |   case Builtin::BI_exception_info: | 
 |     if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, | 
 |                              diag::err_seh___except_filter)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__GetExceptionInfo: | 
 |     if (checkArgCount(TheCall, 1)) | 
 |       return ExprError(); | 
 |  | 
 |     if (CheckCXXThrowOperand( | 
 |             TheCall->getBeginLoc(), | 
 |             Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()), | 
 |             TheCall)) | 
 |       return ExprError(); | 
 |  | 
 |     TheCall->setType(Context.VoidPtrTy); | 
 |     break; | 
 |   case Builtin::BIaddressof: | 
 |   case Builtin::BI__addressof: | 
 |   case Builtin::BIforward: | 
 |   case Builtin::BIforward_like: | 
 |   case Builtin::BImove: | 
 |   case Builtin::BImove_if_noexcept: | 
 |   case Builtin::BIas_const: { | 
 |     // These are all expected to be of the form | 
 |     //   T &/&&/* f(U &/&&) | 
 |     // where T and U only differ in qualification. | 
 |     if (checkArgCount(TheCall, 1)) | 
 |       return ExprError(); | 
 |     QualType Param = FDecl->getParamDecl(0)->getType(); | 
 |     QualType Result = FDecl->getReturnType(); | 
 |     bool ReturnsPointer = BuiltinID == Builtin::BIaddressof || | 
 |                           BuiltinID == Builtin::BI__addressof; | 
 |     if (!(Param->isReferenceType() && | 
 |           (ReturnsPointer ? Result->isAnyPointerType() | 
 |                           : Result->isReferenceType()) && | 
 |           Context.hasSameUnqualifiedType(Param->getPointeeType(), | 
 |                                          Result->getPointeeType()))) { | 
 |       Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported) | 
 |           << FDecl; | 
 |       return ExprError(); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_ptrauth_strip: | 
 |     return PointerAuthStrip(*this, TheCall); | 
 |   case Builtin::BI__builtin_ptrauth_blend_discriminator: | 
 |     return PointerAuthBlendDiscriminator(*this, TheCall); | 
 |   case Builtin::BI__builtin_ptrauth_sign_constant: | 
 |     return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign, | 
 |                                  /*RequireConstant=*/true); | 
 |   case Builtin::BI__builtin_ptrauth_sign_unauthenticated: | 
 |     return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign, | 
 |                                  /*RequireConstant=*/false); | 
 |   case Builtin::BI__builtin_ptrauth_auth: | 
 |     return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth, | 
 |                                  /*RequireConstant=*/false); | 
 |   case Builtin::BI__builtin_ptrauth_sign_generic_data: | 
 |     return PointerAuthSignGenericData(*this, TheCall); | 
 |   case Builtin::BI__builtin_ptrauth_auth_and_resign: | 
 |     return PointerAuthAuthAndResign(*this, TheCall); | 
 |   case Builtin::BI__builtin_ptrauth_string_discriminator: | 
 |     return PointerAuthStringDiscriminator(*this, TheCall); | 
 |  | 
 |   case Builtin::BI__builtin_get_vtable_pointer: | 
 |     return GetVTablePointer(*this, TheCall); | 
 |  | 
 |   // OpenCL v2.0, s6.13.16 - Pipe functions | 
 |   case Builtin::BIread_pipe: | 
 |   case Builtin::BIwrite_pipe: | 
 |     // Since those two functions are declared with var args, we need a semantic | 
 |     // check for the argument. | 
 |     if (OpenCL().checkBuiltinRWPipe(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIreserve_read_pipe: | 
 |   case Builtin::BIreserve_write_pipe: | 
 |   case Builtin::BIwork_group_reserve_read_pipe: | 
 |   case Builtin::BIwork_group_reserve_write_pipe: | 
 |     if (OpenCL().checkBuiltinReserveRWPipe(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIsub_group_reserve_read_pipe: | 
 |   case Builtin::BIsub_group_reserve_write_pipe: | 
 |     if (OpenCL().checkSubgroupExt(TheCall) || | 
 |         OpenCL().checkBuiltinReserveRWPipe(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIcommit_read_pipe: | 
 |   case Builtin::BIcommit_write_pipe: | 
 |   case Builtin::BIwork_group_commit_read_pipe: | 
 |   case Builtin::BIwork_group_commit_write_pipe: | 
 |     if (OpenCL().checkBuiltinCommitRWPipe(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIsub_group_commit_read_pipe: | 
 |   case Builtin::BIsub_group_commit_write_pipe: | 
 |     if (OpenCL().checkSubgroupExt(TheCall) || | 
 |         OpenCL().checkBuiltinCommitRWPipe(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIget_pipe_num_packets: | 
 |   case Builtin::BIget_pipe_max_packets: | 
 |     if (OpenCL().checkBuiltinPipePackets(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIto_global: | 
 |   case Builtin::BIto_local: | 
 |   case Builtin::BIto_private: | 
 |     if (OpenCL().checkBuiltinToAddr(BuiltinID, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. | 
 |   case Builtin::BIenqueue_kernel: | 
 |     if (OpenCL().checkBuiltinEnqueueKernel(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIget_kernel_work_group_size: | 
 |   case Builtin::BIget_kernel_preferred_work_group_size_multiple: | 
 |     if (OpenCL().checkBuiltinKernelWorkGroupSize(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: | 
 |   case Builtin::BIget_kernel_sub_group_count_for_ndrange: | 
 |     if (OpenCL().checkBuiltinNDRangeAndBlock(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_os_log_format: | 
 |     Cleanup.setExprNeedsCleanups(true); | 
 |     [[fallthrough]]; | 
 |   case Builtin::BI__builtin_os_log_format_buffer_size: | 
 |     if (BuiltinOSLogFormat(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_frame_address: | 
 |   case Builtin::BI__builtin_return_address: { | 
 |     if (BuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) | 
 |       return ExprError(); | 
 |  | 
 |     // -Wframe-address warning if non-zero passed to builtin | 
 |     // return/frame address. | 
 |     Expr::EvalResult Result; | 
 |     if (!TheCall->getArg(0)->isValueDependent() && | 
 |         TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext()) && | 
 |         Result.Val.getInt() != 0) | 
 |       Diag(TheCall->getBeginLoc(), diag::warn_frame_address) | 
 |           << ((BuiltinID == Builtin::BI__builtin_return_address) | 
 |                   ? "__builtin_return_address" | 
 |                   : "__builtin_frame_address") | 
 |           << TheCall->getSourceRange(); | 
 |     break; | 
 |   } | 
 |  | 
 |   case Builtin::BI__builtin_nondeterministic_value: { | 
 |     if (BuiltinNonDeterministicValue(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   } | 
 |  | 
 |   // __builtin_elementwise_abs restricts the element type to signed integers or | 
 |   // floating point types only. | 
 |   case Builtin::BI__builtin_elementwise_abs: | 
 |     if (PrepareBuiltinElementwiseMathOneArgCall( | 
 |             TheCall, EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   // These builtins restrict the element type to floating point | 
 |   // types only. | 
 |   case Builtin::BI__builtin_elementwise_acos: | 
 |   case Builtin::BI__builtin_elementwise_asin: | 
 |   case Builtin::BI__builtin_elementwise_atan: | 
 |   case Builtin::BI__builtin_elementwise_ceil: | 
 |   case Builtin::BI__builtin_elementwise_cos: | 
 |   case Builtin::BI__builtin_elementwise_cosh: | 
 |   case Builtin::BI__builtin_elementwise_exp: | 
 |   case Builtin::BI__builtin_elementwise_exp2: | 
 |   case Builtin::BI__builtin_elementwise_exp10: | 
 |   case Builtin::BI__builtin_elementwise_floor: | 
 |   case Builtin::BI__builtin_elementwise_log: | 
 |   case Builtin::BI__builtin_elementwise_log2: | 
 |   case Builtin::BI__builtin_elementwise_log10: | 
 |   case Builtin::BI__builtin_elementwise_roundeven: | 
 |   case Builtin::BI__builtin_elementwise_round: | 
 |   case Builtin::BI__builtin_elementwise_rint: | 
 |   case Builtin::BI__builtin_elementwise_nearbyint: | 
 |   case Builtin::BI__builtin_elementwise_sin: | 
 |   case Builtin::BI__builtin_elementwise_sinh: | 
 |   case Builtin::BI__builtin_elementwise_sqrt: | 
 |   case Builtin::BI__builtin_elementwise_tan: | 
 |   case Builtin::BI__builtin_elementwise_tanh: | 
 |   case Builtin::BI__builtin_elementwise_trunc: | 
 |   case Builtin::BI__builtin_elementwise_canonicalize: | 
 |     if (PrepareBuiltinElementwiseMathOneArgCall( | 
 |             TheCall, EltwiseBuiltinArgTyRestriction::FloatTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_elementwise_fma: | 
 |     if (BuiltinElementwiseTernaryMath(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   // These builtins restrict the element type to floating point | 
 |   // types only, and take in two arguments. | 
 |   case Builtin::BI__builtin_elementwise_minnum: | 
 |   case Builtin::BI__builtin_elementwise_maxnum: | 
 |   case Builtin::BI__builtin_elementwise_minimum: | 
 |   case Builtin::BI__builtin_elementwise_maximum: | 
 |   case Builtin::BI__builtin_elementwise_minimumnum: | 
 |   case Builtin::BI__builtin_elementwise_maximumnum: | 
 |   case Builtin::BI__builtin_elementwise_atan2: | 
 |   case Builtin::BI__builtin_elementwise_fmod: | 
 |   case Builtin::BI__builtin_elementwise_pow: | 
 |     if (BuiltinElementwiseMath(TheCall, | 
 |                                EltwiseBuiltinArgTyRestriction::FloatTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |   // These builtins restrict the element type to integer | 
 |   // types only. | 
 |   case Builtin::BI__builtin_elementwise_add_sat: | 
 |   case Builtin::BI__builtin_elementwise_sub_sat: | 
 |     if (BuiltinElementwiseMath(TheCall, | 
 |                                EltwiseBuiltinArgTyRestriction::IntegerTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_elementwise_fshl: | 
 |   case Builtin::BI__builtin_elementwise_fshr: | 
 |     if (BuiltinElementwiseTernaryMath( | 
 |             TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_elementwise_min: | 
 |   case Builtin::BI__builtin_elementwise_max: | 
 |     if (BuiltinElementwiseMath(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_elementwise_popcount: | 
 |   case Builtin::BI__builtin_elementwise_bitreverse: | 
 |     if (PrepareBuiltinElementwiseMathOneArgCall( | 
 |             TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_elementwise_copysign: { | 
 |     if (checkArgCount(TheCall, 2)) | 
 |       return ExprError(); | 
 |  | 
 |     ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0)); | 
 |     ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1)); | 
 |     if (Magnitude.isInvalid() || Sign.isInvalid()) | 
 |       return ExprError(); | 
 |  | 
 |     QualType MagnitudeTy = Magnitude.get()->getType(); | 
 |     QualType SignTy = Sign.get()->getType(); | 
 |     if (checkMathBuiltinElementType( | 
 |             *this, TheCall->getArg(0)->getBeginLoc(), MagnitudeTy, | 
 |             EltwiseBuiltinArgTyRestriction::FloatTy, 1) || | 
 |         checkMathBuiltinElementType( | 
 |             *this, TheCall->getArg(1)->getBeginLoc(), SignTy, | 
 |             EltwiseBuiltinArgTyRestriction::FloatTy, 2)) { | 
 |       return ExprError(); | 
 |     } | 
 |  | 
 |     if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) { | 
 |       return Diag(Sign.get()->getBeginLoc(), | 
 |                   diag::err_typecheck_call_different_arg_types) | 
 |              << MagnitudeTy << SignTy; | 
 |     } | 
 |  | 
 |     TheCall->setArg(0, Magnitude.get()); | 
 |     TheCall->setArg(1, Sign.get()); | 
 |     TheCall->setType(Magnitude.get()->getType()); | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_elementwise_clzg: | 
 |   case Builtin::BI__builtin_elementwise_ctzg: | 
 |     // These builtins can be unary or binary. Note for empty calls we call the | 
 |     // unary checker in order to not emit an error that says the function | 
 |     // expects 2 arguments, which would be misleading. | 
 |     if (TheCall->getNumArgs() <= 1) { | 
 |       if (PrepareBuiltinElementwiseMathOneArgCall( | 
 |               TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy)) | 
 |         return ExprError(); | 
 |     } else if (BuiltinElementwiseMath( | 
 |                    TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_reduce_max: | 
 |   case Builtin::BI__builtin_reduce_min: { | 
 |     if (PrepareBuiltinReduceMathOneArgCall(TheCall)) | 
 |       return ExprError(); | 
 |  | 
 |     const Expr *Arg = TheCall->getArg(0); | 
 |     const auto *TyA = Arg->getType()->getAs<VectorType>(); | 
 |  | 
 |     QualType ElTy; | 
 |     if (TyA) | 
 |       ElTy = TyA->getElementType(); | 
 |     else if (Arg->getType()->isSizelessVectorType()) | 
 |       ElTy = Arg->getType()->getSizelessVectorEltType(Context); | 
 |  | 
 |     if (ElTy.isNull()) { | 
 |       Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |           << 1 << /* vector ty */ 2 << /* no int */ 0 << /* no fp */ 0 | 
 |           << Arg->getType(); | 
 |       return ExprError(); | 
 |     } | 
 |  | 
 |     TheCall->setType(ElTy); | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_reduce_maximum: | 
 |   case Builtin::BI__builtin_reduce_minimum: { | 
 |     if (PrepareBuiltinReduceMathOneArgCall(TheCall)) | 
 |       return ExprError(); | 
 |  | 
 |     const Expr *Arg = TheCall->getArg(0); | 
 |     const auto *TyA = Arg->getType()->getAs<VectorType>(); | 
 |  | 
 |     QualType ElTy; | 
 |     if (TyA) | 
 |       ElTy = TyA->getElementType(); | 
 |     else if (Arg->getType()->isSizelessVectorType()) | 
 |       ElTy = Arg->getType()->getSizelessVectorEltType(Context); | 
 |  | 
 |     if (ElTy.isNull() || !ElTy->isFloatingType()) { | 
 |       Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |           << 1 << /* vector of */ 4 << /* no int */ 0 << /* fp */ 1 | 
 |           << Arg->getType(); | 
 |       return ExprError(); | 
 |     } | 
 |  | 
 |     TheCall->setType(ElTy); | 
 |     break; | 
 |   } | 
 |  | 
 |   // These builtins support vectors of integers only. | 
 |   // TODO: ADD/MUL should support floating-point types. | 
 |   case Builtin::BI__builtin_reduce_add: | 
 |   case Builtin::BI__builtin_reduce_mul: | 
 |   case Builtin::BI__builtin_reduce_xor: | 
 |   case Builtin::BI__builtin_reduce_or: | 
 |   case Builtin::BI__builtin_reduce_and: { | 
 |     if (PrepareBuiltinReduceMathOneArgCall(TheCall)) | 
 |       return ExprError(); | 
 |  | 
 |     const Expr *Arg = TheCall->getArg(0); | 
 |     const auto *TyA = Arg->getType()->getAs<VectorType>(); | 
 |  | 
 |     QualType ElTy; | 
 |     if (TyA) | 
 |       ElTy = TyA->getElementType(); | 
 |     else if (Arg->getType()->isSizelessVectorType()) | 
 |       ElTy = Arg->getType()->getSizelessVectorEltType(Context); | 
 |  | 
 |     if (ElTy.isNull() || !ElTy->isIntegerType()) { | 
 |       Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |           << 1 << /* vector of */ 4 << /* int */ 1 << /* no fp */ 0 | 
 |           << Arg->getType(); | 
 |       return ExprError(); | 
 |     } | 
 |  | 
 |     TheCall->setType(ElTy); | 
 |     break; | 
 |   } | 
 |  | 
 |   case Builtin::BI__builtin_matrix_transpose: | 
 |     return BuiltinMatrixTranspose(TheCall, TheCallResult); | 
 |  | 
 |   case Builtin::BI__builtin_matrix_column_major_load: | 
 |     return BuiltinMatrixColumnMajorLoad(TheCall, TheCallResult); | 
 |  | 
 |   case Builtin::BI__builtin_matrix_column_major_store: | 
 |     return BuiltinMatrixColumnMajorStore(TheCall, TheCallResult); | 
 |  | 
 |   case Builtin::BI__builtin_verbose_trap: | 
 |     if (!checkBuiltinVerboseTrap(TheCall, *this)) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   case Builtin::BI__builtin_get_device_side_mangled_name: { | 
 |     auto Check = [](CallExpr *TheCall) { | 
 |       if (TheCall->getNumArgs() != 1) | 
 |         return false; | 
 |       auto *DRE = dyn_cast<DeclRefExpr>(TheCall->getArg(0)->IgnoreImpCasts()); | 
 |       if (!DRE) | 
 |         return false; | 
 |       auto *D = DRE->getDecl(); | 
 |       if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) | 
 |         return false; | 
 |       return D->hasAttr<CUDAGlobalAttr>() || D->hasAttr<CUDADeviceAttr>() || | 
 |              D->hasAttr<CUDAConstantAttr>() || D->hasAttr<HIPManagedAttr>(); | 
 |     }; | 
 |     if (!Check(TheCall)) { | 
 |       Diag(TheCall->getBeginLoc(), | 
 |            diag::err_hip_invalid_args_builtin_mangled_name); | 
 |       return ExprError(); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_popcountg: | 
 |     if (BuiltinPopcountg(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   case Builtin::BI__builtin_clzg: | 
 |   case Builtin::BI__builtin_ctzg: | 
 |     if (BuiltinCountZeroBitsGeneric(*this, TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |  | 
 |   case Builtin::BI__builtin_allow_runtime_check: { | 
 |     Expr *Arg = TheCall->getArg(0); | 
 |     // Check if the argument is a string literal. | 
 |     if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) { | 
 |       Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) | 
 |           << Arg->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Builtin::BI__builtin_counted_by_ref: | 
 |     if (BuiltinCountedByRef(TheCall)) | 
 |       return ExprError(); | 
 |     break; | 
 |   } | 
 |  | 
 |   if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall)) | 
 |     return ExprError(); | 
 |  | 
 |   // Since the target specific builtins for each arch overlap, only check those | 
 |   // of the arch we are compiling for. | 
 |   if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) { | 
 |     if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) { | 
 |       assert(Context.getAuxTargetInfo() && | 
 |              "Aux Target Builtin, but not an aux target?"); | 
 |  | 
 |       if (CheckTSBuiltinFunctionCall( | 
 |               *Context.getAuxTargetInfo(), | 
 |               Context.BuiltinInfo.getAuxBuiltinID(BuiltinID), TheCall)) | 
 |         return ExprError(); | 
 |     } else { | 
 |       if (CheckTSBuiltinFunctionCall(Context.getTargetInfo(), BuiltinID, | 
 |                                      TheCall)) | 
 |         return ExprError(); | 
 |     } | 
 |   } | 
 |  | 
 |   return TheCallResult; | 
 | } | 
 |  | 
 | bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { | 
 |   llvm::APSInt Result; | 
 |   // We can't check the value of a dependent argument. | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   // Check constant-ness first. | 
 |   if (BuiltinConstantArg(TheCall, ArgNum, Result)) | 
 |     return true; | 
 |  | 
 |   // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s. | 
 |   if (Result.isShiftedMask() || (~Result).isShiftedMask()) | 
 |     return false; | 
 |  | 
 |   return Diag(TheCall->getBeginLoc(), | 
 |               diag::err_argument_not_contiguous_bit_field) | 
 |          << ArgNum << Arg->getSourceRange(); | 
 | } | 
 |  | 
 | bool Sema::getFormatStringInfo(const Decl *D, unsigned FormatIdx, | 
 |                                unsigned FirstArg, FormatStringInfo *FSI) { | 
 |   bool IsCXXMember = false; | 
 |   if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) | 
 |     IsCXXMember = MD->isInstance(); | 
 |   bool IsVariadic = false; | 
 |   if (const FunctionType *FnTy = D->getFunctionType()) | 
 |     IsVariadic = cast<FunctionProtoType>(FnTy)->isVariadic(); | 
 |   else if (const auto *BD = dyn_cast<BlockDecl>(D)) | 
 |     IsVariadic = BD->isVariadic(); | 
 |   else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D)) | 
 |     IsVariadic = OMD->isVariadic(); | 
 |  | 
 |   return getFormatStringInfo(FormatIdx, FirstArg, IsCXXMember, IsVariadic, FSI); | 
 | } | 
 |  | 
 | bool Sema::getFormatStringInfo(unsigned FormatIdx, unsigned FirstArg, | 
 |                                bool IsCXXMember, bool IsVariadic, | 
 |                                FormatStringInfo *FSI) { | 
 |   if (FirstArg == 0) | 
 |     FSI->ArgPassingKind = FAPK_VAList; | 
 |   else if (IsVariadic) | 
 |     FSI->ArgPassingKind = FAPK_Variadic; | 
 |   else | 
 |     FSI->ArgPassingKind = FAPK_Fixed; | 
 |   FSI->FormatIdx = FormatIdx - 1; | 
 |   FSI->FirstDataArg = FSI->ArgPassingKind == FAPK_VAList ? 0 : FirstArg - 1; | 
 |  | 
 |   // The way the format attribute works in GCC, the implicit this argument | 
 |   // of member functions is counted. However, it doesn't appear in our own | 
 |   // lists, so decrement format_idx in that case. | 
 |   if (IsCXXMember) { | 
 |     if(FSI->FormatIdx == 0) | 
 |       return false; | 
 |     --FSI->FormatIdx; | 
 |     if (FSI->FirstDataArg != 0) | 
 |       --FSI->FirstDataArg; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | /// Checks if a the given expression evaluates to null. | 
 | /// | 
 | /// Returns true if the value evaluates to null. | 
 | static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { | 
 |   // Treat (smart) pointers constructed from nullptr as null, whether we can | 
 |   // const-evaluate them or not. | 
 |   // This must happen first: the smart pointer expr might have _Nonnull type! | 
 |   if (isa<CXXNullPtrLiteralExpr>( | 
 |           IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep, | 
 |                           IgnoreElidableImplicitConstructorSingleStep))) | 
 |     return true; | 
 |  | 
 |   // If the expression has non-null type, it doesn't evaluate to null. | 
 |   if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) { | 
 |     if (*nullability == NullabilityKind::NonNull) | 
 |       return false; | 
 |   } | 
 |  | 
 |   // As a special case, transparent unions initialized with zero are | 
 |   // considered null for the purposes of the nonnull attribute. | 
 |   if (const RecordType *UT = Expr->getType()->getAsUnionType(); | 
 |       UT && | 
 |       UT->getDecl()->getMostRecentDecl()->hasAttr<TransparentUnionAttr>()) { | 
 |     if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(Expr)) | 
 |       if (const auto *ILE = dyn_cast<InitListExpr>(CLE->getInitializer())) | 
 |         Expr = ILE->getInit(0); | 
 |   } | 
 |  | 
 |   bool Result; | 
 |   return (!Expr->isValueDependent() && | 
 |           Expr->EvaluateAsBooleanCondition(Result, S.Context) && | 
 |           !Result); | 
 | } | 
 |  | 
 | static void CheckNonNullArgument(Sema &S, | 
 |                                  const Expr *ArgExpr, | 
 |                                  SourceLocation CallSiteLoc) { | 
 |   if (CheckNonNullExpr(S, ArgExpr)) | 
 |     S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr, | 
 |                           S.PDiag(diag::warn_null_arg) | 
 |                               << ArgExpr->getSourceRange()); | 
 | } | 
 |  | 
 | /// Determine whether the given type has a non-null nullability annotation. | 
 | static bool isNonNullType(QualType type) { | 
 |   if (auto nullability = type->getNullability()) | 
 |     return *nullability == NullabilityKind::NonNull; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | static void CheckNonNullArguments(Sema &S, | 
 |                                   const NamedDecl *FDecl, | 
 |                                   const FunctionProtoType *Proto, | 
 |                                   ArrayRef<const Expr *> Args, | 
 |                                   SourceLocation CallSiteLoc) { | 
 |   assert((FDecl || Proto) && "Need a function declaration or prototype"); | 
 |  | 
 |   // Already checked by constant evaluator. | 
 |   if (S.isConstantEvaluatedContext()) | 
 |     return; | 
 |   // Check the attributes attached to the method/function itself. | 
 |   llvm::SmallBitVector NonNullArgs; | 
 |   if (FDecl) { | 
 |     // Handle the nonnull attribute on the function/method declaration itself. | 
 |     for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { | 
 |       if (!NonNull->args_size()) { | 
 |         // Easy case: all pointer arguments are nonnull. | 
 |         for (const auto *Arg : Args) | 
 |           if (S.isValidPointerAttrType(Arg->getType())) | 
 |             CheckNonNullArgument(S, Arg, CallSiteLoc); | 
 |         return; | 
 |       } | 
 |  | 
 |       for (const ParamIdx &Idx : NonNull->args()) { | 
 |         unsigned IdxAST = Idx.getASTIndex(); | 
 |         if (IdxAST >= Args.size()) | 
 |           continue; | 
 |         if (NonNullArgs.empty()) | 
 |           NonNullArgs.resize(Args.size()); | 
 |         NonNullArgs.set(IdxAST); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (FDecl && (isa<FunctionDecl>(FDecl) || isa<ObjCMethodDecl>(FDecl))) { | 
 |     // Handle the nonnull attribute on the parameters of the | 
 |     // function/method. | 
 |     ArrayRef<ParmVarDecl*> parms; | 
 |     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl)) | 
 |       parms = FD->parameters(); | 
 |     else | 
 |       parms = cast<ObjCMethodDecl>(FDecl)->parameters(); | 
 |  | 
 |     unsigned ParamIndex = 0; | 
 |     for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); | 
 |          I != E; ++I, ++ParamIndex) { | 
 |       const ParmVarDecl *PVD = *I; | 
 |       if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) { | 
 |         if (NonNullArgs.empty()) | 
 |           NonNullArgs.resize(Args.size()); | 
 |  | 
 |         NonNullArgs.set(ParamIndex); | 
 |       } | 
 |     } | 
 |   } else { | 
 |     // If we have a non-function, non-method declaration but no | 
 |     // function prototype, try to dig out the function prototype. | 
 |     if (!Proto) { | 
 |       if (const ValueDecl *VD = dyn_cast<ValueDecl>(FDecl)) { | 
 |         QualType type = VD->getType().getNonReferenceType(); | 
 |         if (auto pointerType = type->getAs<PointerType>()) | 
 |           type = pointerType->getPointeeType(); | 
 |         else if (auto blockType = type->getAs<BlockPointerType>()) | 
 |           type = blockType->getPointeeType(); | 
 |         // FIXME: data member pointers? | 
 |  | 
 |         // Dig out the function prototype, if there is one. | 
 |         Proto = type->getAs<FunctionProtoType>(); | 
 |       } | 
 |     } | 
 |  | 
 |     // Fill in non-null argument information from the nullability | 
 |     // information on the parameter types (if we have them). | 
 |     if (Proto) { | 
 |       unsigned Index = 0; | 
 |       for (auto paramType : Proto->getParamTypes()) { | 
 |         if (isNonNullType(paramType)) { | 
 |           if (NonNullArgs.empty()) | 
 |             NonNullArgs.resize(Args.size()); | 
 |  | 
 |           NonNullArgs.set(Index); | 
 |         } | 
 |  | 
 |         ++Index; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Check for non-null arguments. | 
 |   for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); | 
 |        ArgIndex != ArgIndexEnd; ++ArgIndex) { | 
 |     if (NonNullArgs[ArgIndex]) | 
 |       CheckNonNullArgument(S, Args[ArgIndex], Args[ArgIndex]->getExprLoc()); | 
 |   } | 
 | } | 
 |  | 
 | void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl, | 
 |                              StringRef ParamName, QualType ArgTy, | 
 |                              QualType ParamTy) { | 
 |  | 
 |   // If a function accepts a pointer or reference type | 
 |   if (!ParamTy->isPointerType() && !ParamTy->isReferenceType()) | 
 |     return; | 
 |  | 
 |   // If the parameter is a pointer type, get the pointee type for the | 
 |   // argument too. If the parameter is a reference type, don't try to get | 
 |   // the pointee type for the argument. | 
 |   if (ParamTy->isPointerType()) | 
 |     ArgTy = ArgTy->getPointeeType(); | 
 |  | 
 |   // Remove reference or pointer | 
 |   ParamTy = ParamTy->getPointeeType(); | 
 |  | 
 |   // Find expected alignment, and the actual alignment of the passed object. | 
 |   // getTypeAlignInChars requires complete types | 
 |   if (ArgTy.isNull() || ParamTy->isDependentType() || | 
 |       ParamTy->isIncompleteType() || ArgTy->isIncompleteType() || | 
 |       ParamTy->isUndeducedType() || ArgTy->isUndeducedType()) | 
 |     return; | 
 |  | 
 |   CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy); | 
 |   CharUnits ArgAlign = Context.getTypeAlignInChars(ArgTy); | 
 |  | 
 |   // If the argument is less aligned than the parameter, there is a | 
 |   // potential alignment issue. | 
 |   if (ArgAlign < ParamAlign) | 
 |     Diag(Loc, diag::warn_param_mismatched_alignment) | 
 |         << (int)ArgAlign.getQuantity() << (int)ParamAlign.getQuantity() | 
 |         << ParamName << (FDecl != nullptr) << FDecl; | 
 | } | 
 |  | 
 | void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction, | 
 |                                   const Expr *ThisArg, | 
 |                                   ArrayRef<const Expr *> Args) { | 
 |   if (!FD || Args.empty()) | 
 |     return; | 
 |   auto GetArgAt = [&](int Idx) -> const Expr * { | 
 |     if (Idx == LifetimeCaptureByAttr::Global || | 
 |         Idx == LifetimeCaptureByAttr::Unknown) | 
 |       return nullptr; | 
 |     if (IsMemberFunction && Idx == 0) | 
 |       return ThisArg; | 
 |     return Args[Idx - IsMemberFunction]; | 
 |   }; | 
 |   auto HandleCaptureByAttr = [&](const LifetimeCaptureByAttr *Attr, | 
 |                                  unsigned ArgIdx) { | 
 |     if (!Attr) | 
 |       return; | 
 |  | 
 |     Expr *Captured = const_cast<Expr *>(GetArgAt(ArgIdx)); | 
 |     for (int CapturingParamIdx : Attr->params()) { | 
 |       // lifetime_capture_by(this) case is handled in the lifetimebound expr | 
 |       // initialization codepath. | 
 |       if (CapturingParamIdx == LifetimeCaptureByAttr::This && | 
 |           isa<CXXConstructorDecl>(FD)) | 
 |         continue; | 
 |       Expr *Capturing = const_cast<Expr *>(GetArgAt(CapturingParamIdx)); | 
 |       CapturingEntity CE{Capturing}; | 
 |       // Ensure that 'Captured' outlives the 'Capturing' entity. | 
 |       checkCaptureByLifetime(*this, CE, Captured); | 
 |     } | 
 |   }; | 
 |   for (unsigned I = 0; I < FD->getNumParams(); ++I) | 
 |     HandleCaptureByAttr(FD->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>(), | 
 |                         I + IsMemberFunction); | 
 |   // Check when the implicit object param is captured. | 
 |   if (IsMemberFunction) { | 
 |     TypeSourceInfo *TSI = FD->getTypeSourceInfo(); | 
 |     if (!TSI) | 
 |       return; | 
 |     AttributedTypeLoc ATL; | 
 |     for (TypeLoc TL = TSI->getTypeLoc(); | 
 |          (ATL = TL.getAsAdjusted<AttributedTypeLoc>()); | 
 |          TL = ATL.getModifiedLoc()) | 
 |       HandleCaptureByAttr(ATL.getAttrAs<LifetimeCaptureByAttr>(), 0); | 
 |   } | 
 | } | 
 |  | 
 | void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, | 
 |                      const Expr *ThisArg, ArrayRef<const Expr *> Args, | 
 |                      bool IsMemberFunction, SourceLocation Loc, | 
 |                      SourceRange Range, VariadicCallType CallType) { | 
 |   // FIXME: We should check as much as we can in the template definition. | 
 |   if (CurContext->isDependentContext()) | 
 |     return; | 
 |  | 
 |   // Printf and scanf checking. | 
 |   llvm::SmallBitVector CheckedVarArgs; | 
 |   if (FDecl) { | 
 |     for (const auto *I : FDecl->specific_attrs<FormatMatchesAttr>()) { | 
 |       // Only create vector if there are format attributes. | 
 |       CheckedVarArgs.resize(Args.size()); | 
 |       CheckFormatString(I, Args, IsMemberFunction, CallType, Loc, Range, | 
 |                         CheckedVarArgs); | 
 |     } | 
 |  | 
 |     for (const auto *I : FDecl->specific_attrs<FormatAttr>()) { | 
 |       CheckedVarArgs.resize(Args.size()); | 
 |       CheckFormatArguments(I, Args, IsMemberFunction, CallType, Loc, Range, | 
 |                            CheckedVarArgs); | 
 |     } | 
 |   } | 
 |  | 
 |   // Refuse POD arguments that weren't caught by the format string | 
 |   // checks above. | 
 |   auto *FD = dyn_cast_or_null<FunctionDecl>(FDecl); | 
 |   if (CallType != VariadicCallType::DoesNotApply && | 
 |       (!FD || FD->getBuiltinID() != Builtin::BI__noop)) { | 
 |     unsigned NumParams = Proto ? Proto->getNumParams() | 
 |                          : isa_and_nonnull<FunctionDecl>(FDecl) | 
 |                              ? cast<FunctionDecl>(FDecl)->getNumParams() | 
 |                          : isa_and_nonnull<ObjCMethodDecl>(FDecl) | 
 |                              ? cast<ObjCMethodDecl>(FDecl)->param_size() | 
 |                              : 0; | 
 |  | 
 |     for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) { | 
 |       // Args[ArgIdx] can be null in malformed code. | 
 |       if (const Expr *Arg = Args[ArgIdx]) { | 
 |         if (CheckedVarArgs.empty() || !CheckedVarArgs[ArgIdx]) | 
 |           checkVariadicArgument(Arg, CallType); | 
 |       } | 
 |     } | 
 |   } | 
 |   if (FD) | 
 |     checkLifetimeCaptureBy(FD, IsMemberFunction, ThisArg, Args); | 
 |   if (FDecl || Proto) { | 
 |     CheckNonNullArguments(*this, FDecl, Proto, Args, Loc); | 
 |  | 
 |     // Type safety checking. | 
 |     if (FDecl) { | 
 |       for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) | 
 |         CheckArgumentWithTypeTag(I, Args, Loc); | 
 |     } | 
 |   } | 
 |  | 
 |   // Check that passed arguments match the alignment of original arguments. | 
 |   // Try to get the missing prototype from the declaration. | 
 |   if (!Proto && FDecl) { | 
 |     const auto *FT = FDecl->getFunctionType(); | 
 |     if (isa_and_nonnull<FunctionProtoType>(FT)) | 
 |       Proto = cast<FunctionProtoType>(FDecl->getFunctionType()); | 
 |   } | 
 |   if (Proto) { | 
 |     // For variadic functions, we may have more args than parameters. | 
 |     // For some K&R functions, we may have less args than parameters. | 
 |     const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size()); | 
 |     bool IsScalableRet = Proto->getReturnType()->isSizelessVectorType(); | 
 |     bool IsScalableArg = false; | 
 |     for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) { | 
 |       // Args[ArgIdx] can be null in malformed code. | 
 |       if (const Expr *Arg = Args[ArgIdx]) { | 
 |         if (Arg->containsErrors()) | 
 |           continue; | 
 |  | 
 |         if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg && | 
 |             FDecl->hasLinkage() && | 
 |             FDecl->getFormalLinkage() != Linkage::Internal && | 
 |             CallType == VariadicCallType::DoesNotApply) | 
 |           PPC().checkAIXMemberAlignment((Arg->getExprLoc()), Arg); | 
 |  | 
 |         QualType ParamTy = Proto->getParamType(ArgIdx); | 
 |         if (ParamTy->isSizelessVectorType()) | 
 |           IsScalableArg = true; | 
 |         QualType ArgTy = Arg->getType(); | 
 |         CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1), | 
 |                           ArgTy, ParamTy); | 
 |       } | 
 |     } | 
 |  | 
 |     // If the callee has an AArch64 SME attribute to indicate that it is an | 
 |     // __arm_streaming function, then the caller requires SME to be available. | 
 |     FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo(); | 
 |     if (ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask) { | 
 |       if (auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) { | 
 |         llvm::StringMap<bool> CallerFeatureMap; | 
 |         Context.getFunctionFeatureMap(CallerFeatureMap, CallerFD); | 
 |         if (!CallerFeatureMap.contains("sme")) | 
 |           Diag(Loc, diag::err_sme_call_in_non_sme_target); | 
 |       } else if (!Context.getTargetInfo().hasFeature("sme")) { | 
 |         Diag(Loc, diag::err_sme_call_in_non_sme_target); | 
 |       } | 
 |     } | 
 |  | 
 |     // If the call requires a streaming-mode change and has scalable vector | 
 |     // arguments or return values, then warn the user that the streaming and | 
 |     // non-streaming vector lengths may be different. | 
 |     // When both streaming and non-streaming vector lengths are defined and | 
 |     // mismatched, produce an error. | 
 |     const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext); | 
 |     if (CallerFD && (!FD || !FD->getBuiltinID()) && | 
 |         (IsScalableArg || IsScalableRet)) { | 
 |       bool IsCalleeStreaming = | 
 |           ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask; | 
 |       bool IsCalleeStreamingCompatible = | 
 |           ExtInfo.AArch64SMEAttributes & | 
 |           FunctionType::SME_PStateSMCompatibleMask; | 
 |       SemaARM::ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); | 
 |       if (!IsCalleeStreamingCompatible && | 
 |           (CallerFnType == SemaARM::ArmStreamingCompatible || | 
 |            ((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) { | 
 |         const LangOptions &LO = getLangOpts(); | 
 |         unsigned VL = LO.VScaleMin * 128; | 
 |         unsigned SVL = LO.VScaleStreamingMin * 128; | 
 |         bool IsVLMismatch = VL && SVL && VL != SVL; | 
 |  | 
 |         auto EmitDiag = [&](bool IsArg) { | 
 |           if (IsVLMismatch) { | 
 |             if (CallerFnType == SemaARM::ArmStreamingCompatible) | 
 |               // Emit warning for streaming-compatible callers | 
 |               Diag(Loc, diag::warn_sme_streaming_compatible_vl_mismatch) | 
 |                   << IsArg << IsCalleeStreaming << SVL << VL; | 
 |             else | 
 |               // Emit error otherwise | 
 |               Diag(Loc, diag::err_sme_streaming_transition_vl_mismatch) | 
 |                   << IsArg << SVL << VL; | 
 |           } else | 
 |             Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) | 
 |                 << IsArg; | 
 |         }; | 
 |  | 
 |         if (IsScalableArg) | 
 |           EmitDiag(true); | 
 |         if (IsScalableRet) | 
 |           EmitDiag(false); | 
 |       } | 
 |     } | 
 |  | 
 |     FunctionType::ArmStateValue CalleeArmZAState = | 
 |         FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes); | 
 |     FunctionType::ArmStateValue CalleeArmZT0State = | 
 |         FunctionType::getArmZT0State(ExtInfo.AArch64SMEAttributes); | 
 |     if (CalleeArmZAState != FunctionType::ARM_None || | 
 |         CalleeArmZT0State != FunctionType::ARM_None) { | 
 |       bool CallerHasZAState = false; | 
 |       bool CallerHasZT0State = false; | 
 |       if (CallerFD) { | 
 |         auto *Attr = CallerFD->getAttr<ArmNewAttr>(); | 
 |         if (Attr && Attr->isNewZA()) | 
 |           CallerHasZAState = true; | 
 |         if (Attr && Attr->isNewZT0()) | 
 |           CallerHasZT0State = true; | 
 |         if (const auto *FPT = CallerFD->getType()->getAs<FunctionProtoType>()) { | 
 |           CallerHasZAState |= | 
 |               FunctionType::getArmZAState( | 
 |                   FPT->getExtProtoInfo().AArch64SMEAttributes) != | 
 |               FunctionType::ARM_None; | 
 |           CallerHasZT0State |= | 
 |               FunctionType::getArmZT0State( | 
 |                   FPT->getExtProtoInfo().AArch64SMEAttributes) != | 
 |               FunctionType::ARM_None; | 
 |         } | 
 |       } | 
 |  | 
 |       if (CalleeArmZAState != FunctionType::ARM_None && !CallerHasZAState) | 
 |         Diag(Loc, diag::err_sme_za_call_no_za_state); | 
 |  | 
 |       if (CalleeArmZT0State != FunctionType::ARM_None && !CallerHasZT0State) | 
 |         Diag(Loc, diag::err_sme_zt0_call_no_zt0_state); | 
 |  | 
 |       if (CallerHasZAState && CalleeArmZAState == FunctionType::ARM_None && | 
 |           CalleeArmZT0State != FunctionType::ARM_None) { | 
 |         Diag(Loc, diag::err_sme_unimplemented_za_save_restore); | 
 |         Diag(Loc, diag::note_sme_use_preserves_za); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (FDecl && FDecl->hasAttr<AllocAlignAttr>()) { | 
 |     auto *AA = FDecl->getAttr<AllocAlignAttr>(); | 
 |     const Expr *Arg = Args[AA->getParamIndex().getASTIndex()]; | 
 |     if (!Arg->isValueDependent()) { | 
 |       Expr::EvalResult Align; | 
 |       if (Arg->EvaluateAsInt(Align, Context)) { | 
 |         const llvm::APSInt &I = Align.Val.getInt(); | 
 |         if (!I.isPowerOf2()) | 
 |           Diag(Arg->getExprLoc(), diag::warn_alignment_not_power_of_two) | 
 |               << Arg->getSourceRange(); | 
 |  | 
 |         if (I > Sema::MaximumAlignment) | 
 |           Diag(Arg->getExprLoc(), diag::warn_assume_aligned_too_great) | 
 |               << Arg->getSourceRange() << Sema::MaximumAlignment; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (FD) | 
 |     diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc); | 
 | } | 
 |  | 
 | void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) { | 
 |   if (TemplateDecl *Decl = AutoT->getTypeConstraintConcept()) { | 
 |     DiagnoseUseOfDecl(Decl, Loc); | 
 |   } | 
 | } | 
 |  | 
 | void Sema::CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType, | 
 |                                 ArrayRef<const Expr *> Args, | 
 |                                 const FunctionProtoType *Proto, | 
 |                                 SourceLocation Loc) { | 
 |   VariadicCallType CallType = Proto->isVariadic() | 
 |                                   ? VariadicCallType::Constructor | 
 |                                   : VariadicCallType::DoesNotApply; | 
 |  | 
 |   auto *Ctor = cast<CXXConstructorDecl>(FDecl); | 
 |   CheckArgAlignment( | 
 |       Loc, FDecl, "'this'", Context.getPointerType(ThisType), | 
 |       Context.getPointerType(Ctor->getFunctionObjectParameterType())); | 
 |  | 
 |   checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true, | 
 |             Loc, SourceRange(), CallType); | 
 | } | 
 |  | 
 | bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, | 
 |                              const FunctionProtoType *Proto) { | 
 |   bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) && | 
 |                               isa<CXXMethodDecl>(FDecl); | 
 |   bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) || | 
 |                           IsMemberOperatorCall; | 
 |   VariadicCallType CallType = getVariadicCallType(FDecl, Proto, | 
 |                                                   TheCall->getCallee()); | 
 |   Expr** Args = TheCall->getArgs(); | 
 |   unsigned NumArgs = TheCall->getNumArgs(); | 
 |  | 
 |   Expr *ImplicitThis = nullptr; | 
 |   if (IsMemberOperatorCall && !FDecl->hasCXXExplicitFunctionObjectParameter()) { | 
 |     // If this is a call to a member operator, hide the first | 
 |     // argument from checkCall. | 
 |     // FIXME: Our choice of AST representation here is less than ideal. | 
 |     ImplicitThis = Args[0]; | 
 |     ++Args; | 
 |     --NumArgs; | 
 |   } else if (IsMemberFunction && !FDecl->isStatic() && | 
 |              !FDecl->hasCXXExplicitFunctionObjectParameter()) | 
 |     ImplicitThis = | 
 |         cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument(); | 
 |  | 
 |   if (ImplicitThis) { | 
 |     // ImplicitThis may or may not be a pointer, depending on whether . or -> is | 
 |     // used. | 
 |     QualType ThisType = ImplicitThis->getType(); | 
 |     if (!ThisType->isPointerType()) { | 
 |       assert(!ThisType->isReferenceType()); | 
 |       ThisType = Context.getPointerType(ThisType); | 
 |     } | 
 |  | 
 |     QualType ThisTypeFromDecl = Context.getPointerType( | 
 |         cast<CXXMethodDecl>(FDecl)->getFunctionObjectParameterType()); | 
 |  | 
 |     CheckArgAlignment(TheCall->getRParenLoc(), FDecl, "'this'", ThisType, | 
 |                       ThisTypeFromDecl); | 
 |   } | 
 |  | 
 |   checkCall(FDecl, Proto, ImplicitThis, llvm::ArrayRef(Args, NumArgs), | 
 |             IsMemberFunction, TheCall->getRParenLoc(), | 
 |             TheCall->getCallee()->getSourceRange(), CallType); | 
 |  | 
 |   IdentifierInfo *FnInfo = FDecl->getIdentifier(); | 
 |   // None of the checks below are needed for functions that don't have | 
 |   // simple names (e.g., C++ conversion functions). | 
 |   if (!FnInfo) | 
 |     return false; | 
 |  | 
 |   // Enforce TCB except for builtin calls, which are always allowed. | 
 |   if (FDecl->getBuiltinID() == 0) | 
 |     CheckTCBEnforcement(TheCall->getExprLoc(), FDecl); | 
 |  | 
 |   CheckAbsoluteValueFunction(TheCall, FDecl); | 
 |   CheckMaxUnsignedZero(TheCall, FDecl); | 
 |   CheckInfNaNFunction(TheCall, FDecl); | 
 |  | 
 |   if (getLangOpts().ObjC) | 
 |     ObjC().DiagnoseCStringFormatDirectiveInCFAPI(FDecl, Args, NumArgs); | 
 |  | 
 |   unsigned CMId = FDecl->getMemoryFunctionKind(); | 
 |  | 
 |   // Handle memory setting and copying functions. | 
 |   switch (CMId) { | 
 |   case 0: | 
 |     return false; | 
 |   case Builtin::BIstrlcpy: // fallthrough | 
 |   case Builtin::BIstrlcat: | 
 |     CheckStrlcpycatArguments(TheCall, FnInfo); | 
 |     break; | 
 |   case Builtin::BIstrncat: | 
 |     CheckStrncatArguments(TheCall, FnInfo); | 
 |     break; | 
 |   case Builtin::BIfree: | 
 |     CheckFreeArguments(TheCall); | 
 |     break; | 
 |   default: | 
 |     CheckMemaccessArguments(TheCall, CMId, FnInfo); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, | 
 |                             const FunctionProtoType *Proto) { | 
 |   QualType Ty; | 
 |   if (const auto *V = dyn_cast<VarDecl>(NDecl)) | 
 |     Ty = V->getType().getNonReferenceType(); | 
 |   else if (const auto *F = dyn_cast<FieldDecl>(NDecl)) | 
 |     Ty = F->getType().getNonReferenceType(); | 
 |   else | 
 |     return false; | 
 |  | 
 |   if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() && | 
 |       !Ty->isFunctionProtoType()) | 
 |     return false; | 
 |  | 
 |   VariadicCallType CallType; | 
 |   if (!Proto || !Proto->isVariadic()) { | 
 |     CallType = VariadicCallType::DoesNotApply; | 
 |   } else if (Ty->isBlockPointerType()) { | 
 |     CallType = VariadicCallType::Block; | 
 |   } else { // Ty->isFunctionPointerType() | 
 |     CallType = VariadicCallType::Function; | 
 |   } | 
 |  | 
 |   checkCall(NDecl, Proto, /*ThisArg=*/nullptr, | 
 |             llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), | 
 |             /*IsMemberFunction=*/false, TheCall->getRParenLoc(), | 
 |             TheCall->getCallee()->getSourceRange(), CallType); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { | 
 |   VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto, | 
 |                                                   TheCall->getCallee()); | 
 |   checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr, | 
 |             llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), | 
 |             /*IsMemberFunction=*/false, TheCall->getRParenLoc(), | 
 |             TheCall->getCallee()->getSourceRange(), CallType); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { | 
 |   if (!llvm::isValidAtomicOrderingCABI(Ordering)) | 
 |     return false; | 
 |  | 
 |   auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering; | 
 |   switch (Op) { | 
 |   case AtomicExpr::AO__c11_atomic_init: | 
 |   case AtomicExpr::AO__opencl_atomic_init: | 
 |     llvm_unreachable("There is no ordering argument for an init"); | 
 |  | 
 |   case AtomicExpr::AO__c11_atomic_load: | 
 |   case AtomicExpr::AO__opencl_atomic_load: | 
 |   case AtomicExpr::AO__hip_atomic_load: | 
 |   case AtomicExpr::AO__atomic_load_n: | 
 |   case AtomicExpr::AO__atomic_load: | 
 |   case AtomicExpr::AO__scoped_atomic_load_n: | 
 |   case AtomicExpr::AO__scoped_atomic_load: | 
 |     return OrderingCABI != llvm::AtomicOrderingCABI::release && | 
 |            OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; | 
 |  | 
 |   case AtomicExpr::AO__c11_atomic_store: | 
 |   case AtomicExpr::AO__opencl_atomic_store: | 
 |   case AtomicExpr::AO__hip_atomic_store: | 
 |   case AtomicExpr::AO__atomic_store: | 
 |   case AtomicExpr::AO__atomic_store_n: | 
 |   case AtomicExpr::AO__scoped_atomic_store: | 
 |   case AtomicExpr::AO__scoped_atomic_store_n: | 
 |   case AtomicExpr::AO__atomic_clear: | 
 |     return OrderingCABI != llvm::AtomicOrderingCABI::consume && | 
 |            OrderingCABI != llvm::AtomicOrderingCABI::acquire && | 
 |            OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; | 
 |  | 
 |   default: | 
 |     return true; | 
 |   } | 
 | } | 
 |  | 
 | ExprResult Sema::AtomicOpsOverloaded(ExprResult TheCallResult, | 
 |                                      AtomicExpr::AtomicOp Op) { | 
 |   CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); | 
 |   DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); | 
 |   MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()}; | 
 |   return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()}, | 
 |                          DRE->getSourceRange(), TheCall->getRParenLoc(), Args, | 
 |                          Op); | 
 | } | 
 |  | 
 | ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, | 
 |                                  SourceLocation RParenLoc, MultiExprArg Args, | 
 |                                  AtomicExpr::AtomicOp Op, | 
 |                                  AtomicArgumentOrder ArgOrder) { | 
 |   // All the non-OpenCL operations take one of the following forms. | 
 |   // The OpenCL operations take the __c11 forms with one extra argument for | 
 |   // synchronization scope. | 
 |   enum { | 
 |     // C    __c11_atomic_init(A *, C) | 
 |     Init, | 
 |  | 
 |     // C    __c11_atomic_load(A *, int) | 
 |     Load, | 
 |  | 
 |     // void __atomic_load(A *, CP, int) | 
 |     LoadCopy, | 
 |  | 
 |     // void __atomic_store(A *, CP, int) | 
 |     Copy, | 
 |  | 
 |     // C    __c11_atomic_add(A *, M, int) | 
 |     Arithmetic, | 
 |  | 
 |     // C    __atomic_exchange_n(A *, CP, int) | 
 |     Xchg, | 
 |  | 
 |     // void __atomic_exchange(A *, C *, CP, int) | 
 |     GNUXchg, | 
 |  | 
 |     // bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int) | 
 |     C11CmpXchg, | 
 |  | 
 |     // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) | 
 |     GNUCmpXchg, | 
 |  | 
 |     // bool __atomic_test_and_set(A *, int) | 
 |     TestAndSetByte, | 
 |  | 
 |     // void __atomic_clear(A *, int) | 
 |     ClearByte, | 
 |   } Form = Init; | 
 |  | 
 |   const unsigned NumForm = ClearByte + 1; | 
 |   const unsigned NumArgs[] = {2, 2, 3, 3, 3, 3, 4, 5, 6, 2, 2}; | 
 |   const unsigned NumVals[] = {1, 0, 1, 1, 1, 1, 2, 2, 3, 0, 0}; | 
 |   // where: | 
 |   //   C is an appropriate type, | 
 |   //   A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins, | 
 |   //   CP is C for __c11 builtins and GNU _n builtins and is C * otherwise, | 
 |   //   M is C if C is an integer, and ptrdiff_t if C is a pointer, and | 
 |   //   the int parameters are for orderings. | 
 |  | 
 |   static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm | 
 |       && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm, | 
 |       "need to update code for modified forms"); | 
 |   static_assert(AtomicExpr::AO__atomic_add_fetch == 0 && | 
 |                     AtomicExpr::AO__atomic_xor_fetch + 1 == | 
 |                         AtomicExpr::AO__c11_atomic_compare_exchange_strong, | 
 |                 "need to update code for modified C11 atomics"); | 
 |   bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_compare_exchange_strong && | 
 |                   Op <= AtomicExpr::AO__opencl_atomic_store; | 
 |   bool IsHIP = Op >= AtomicExpr::AO__hip_atomic_compare_exchange_strong && | 
 |                Op <= AtomicExpr::AO__hip_atomic_store; | 
 |   bool IsScoped = Op >= AtomicExpr::AO__scoped_atomic_add_fetch && | 
 |                   Op <= AtomicExpr::AO__scoped_atomic_xor_fetch; | 
 |   bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_compare_exchange_strong && | 
 |                 Op <= AtomicExpr::AO__c11_atomic_store) || | 
 |                IsOpenCL; | 
 |   bool IsN = Op == AtomicExpr::AO__atomic_load_n || | 
 |              Op == AtomicExpr::AO__atomic_store_n || | 
 |              Op == AtomicExpr::AO__atomic_exchange_n || | 
 |              Op == AtomicExpr::AO__atomic_compare_exchange_n || | 
 |              Op == AtomicExpr::AO__scoped_atomic_load_n || | 
 |              Op == AtomicExpr::AO__scoped_atomic_store_n || | 
 |              Op == AtomicExpr::AO__scoped_atomic_exchange_n || | 
 |              Op == AtomicExpr::AO__scoped_atomic_compare_exchange_n; | 
 |   // Bit mask for extra allowed value types other than integers for atomic | 
 |   // arithmetic operations. Add/sub allow pointer and floating point. Min/max | 
 |   // allow floating point. | 
 |   enum ArithOpExtraValueType { | 
 |     AOEVT_None = 0, | 
 |     AOEVT_Pointer = 1, | 
 |     AOEVT_FP = 2, | 
 |   }; | 
 |   unsigned ArithAllows = AOEVT_None; | 
 |  | 
 |   switch (Op) { | 
 |   case AtomicExpr::AO__c11_atomic_init: | 
 |   case AtomicExpr::AO__opencl_atomic_init: | 
 |     Form = Init; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__c11_atomic_load: | 
 |   case AtomicExpr::AO__opencl_atomic_load: | 
 |   case AtomicExpr::AO__hip_atomic_load: | 
 |   case AtomicExpr::AO__atomic_load_n: | 
 |   case AtomicExpr::AO__scoped_atomic_load_n: | 
 |     Form = Load; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__atomic_load: | 
 |   case AtomicExpr::AO__scoped_atomic_load: | 
 |     Form = LoadCopy; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__c11_atomic_store: | 
 |   case AtomicExpr::AO__opencl_atomic_store: | 
 |   case AtomicExpr::AO__hip_atomic_store: | 
 |   case AtomicExpr::AO__atomic_store: | 
 |   case AtomicExpr::AO__atomic_store_n: | 
 |   case AtomicExpr::AO__scoped_atomic_store: | 
 |   case AtomicExpr::AO__scoped_atomic_store_n: | 
 |     Form = Copy; | 
 |     break; | 
 |   case AtomicExpr::AO__atomic_fetch_add: | 
 |   case AtomicExpr::AO__atomic_fetch_sub: | 
 |   case AtomicExpr::AO__atomic_add_fetch: | 
 |   case AtomicExpr::AO__atomic_sub_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_add: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_sub: | 
 |   case AtomicExpr::AO__scoped_atomic_add_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_sub_fetch: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_add: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_sub: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_add: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_sub: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_add: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_sub: | 
 |     ArithAllows = AOEVT_Pointer | AOEVT_FP; | 
 |     Form = Arithmetic; | 
 |     break; | 
 |   case AtomicExpr::AO__atomic_fetch_max: | 
 |   case AtomicExpr::AO__atomic_fetch_min: | 
 |   case AtomicExpr::AO__atomic_max_fetch: | 
 |   case AtomicExpr::AO__atomic_min_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_max: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_min: | 
 |   case AtomicExpr::AO__scoped_atomic_max_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_min_fetch: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_max: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_min: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_max: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_min: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_max: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_min: | 
 |     ArithAllows = AOEVT_FP; | 
 |     Form = Arithmetic; | 
 |     break; | 
 |   case AtomicExpr::AO__c11_atomic_fetch_and: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_or: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_xor: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_and: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_or: | 
 |   case AtomicExpr::AO__hip_atomic_fetch_xor: | 
 |   case AtomicExpr::AO__c11_atomic_fetch_nand: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_and: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_or: | 
 |   case AtomicExpr::AO__opencl_atomic_fetch_xor: | 
 |   case AtomicExpr::AO__atomic_fetch_and: | 
 |   case AtomicExpr::AO__atomic_fetch_or: | 
 |   case AtomicExpr::AO__atomic_fetch_xor: | 
 |   case AtomicExpr::AO__atomic_fetch_nand: | 
 |   case AtomicExpr::AO__atomic_and_fetch: | 
 |   case AtomicExpr::AO__atomic_or_fetch: | 
 |   case AtomicExpr::AO__atomic_xor_fetch: | 
 |   case AtomicExpr::AO__atomic_nand_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_and: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_or: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_xor: | 
 |   case AtomicExpr::AO__scoped_atomic_fetch_nand: | 
 |   case AtomicExpr::AO__scoped_atomic_and_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_or_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_xor_fetch: | 
 |   case AtomicExpr::AO__scoped_atomic_nand_fetch: | 
 |     Form = Arithmetic; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__c11_atomic_exchange: | 
 |   case AtomicExpr::AO__hip_atomic_exchange: | 
 |   case AtomicExpr::AO__opencl_atomic_exchange: | 
 |   case AtomicExpr::AO__atomic_exchange_n: | 
 |   case AtomicExpr::AO__scoped_atomic_exchange_n: | 
 |     Form = Xchg; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__atomic_exchange: | 
 |   case AtomicExpr::AO__scoped_atomic_exchange: | 
 |     Form = GNUXchg; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__c11_atomic_compare_exchange_strong: | 
 |   case AtomicExpr::AO__c11_atomic_compare_exchange_weak: | 
 |   case AtomicExpr::AO__hip_atomic_compare_exchange_strong: | 
 |   case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: | 
 |   case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: | 
 |   case AtomicExpr::AO__hip_atomic_compare_exchange_weak: | 
 |     Form = C11CmpXchg; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__atomic_compare_exchange: | 
 |   case AtomicExpr::AO__atomic_compare_exchange_n: | 
 |   case AtomicExpr::AO__scoped_atomic_compare_exchange: | 
 |   case AtomicExpr::AO__scoped_atomic_compare_exchange_n: | 
 |     Form = GNUCmpXchg; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__atomic_test_and_set: | 
 |     Form = TestAndSetByte; | 
 |     break; | 
 |  | 
 |   case AtomicExpr::AO__atomic_clear: | 
 |     Form = ClearByte; | 
 |     break; | 
 |   } | 
 |  | 
 |   unsigned AdjustedNumArgs = NumArgs[Form]; | 
 |   if ((IsOpenCL || IsHIP || IsScoped) && | 
 |       Op != AtomicExpr::AO__opencl_atomic_init) | 
 |     ++AdjustedNumArgs; | 
 |   // Check we have the right number of arguments. | 
 |   if (Args.size() < AdjustedNumArgs) { | 
 |     Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args) | 
 |         << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) | 
 |         << /*is non object*/ 0 << ExprRange; | 
 |     return ExprError(); | 
 |   } else if (Args.size() > AdjustedNumArgs) { | 
 |     Diag(Args[AdjustedNumArgs]->getBeginLoc(), | 
 |          diag::err_typecheck_call_too_many_args) | 
 |         << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size()) | 
 |         << /*is non object*/ 0 << ExprRange; | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // Inspect the first argument of the atomic operation. | 
 |   Expr *Ptr = Args[0]; | 
 |   ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); | 
 |   if (ConvertedPtr.isInvalid()) | 
 |     return ExprError(); | 
 |  | 
 |   Ptr = ConvertedPtr.get(); | 
 |   const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); | 
 |   if (!pointerType) { | 
 |     Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) | 
 |         << Ptr->getType() << 0 << Ptr->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // For a __c11 builtin, this should be a pointer to an _Atomic type. | 
 |   QualType AtomTy = pointerType->getPointeeType(); // 'A' | 
 |   QualType ValType = AtomTy; // 'C' | 
 |   if (IsC11) { | 
 |     if (!AtomTy->isAtomicType()) { | 
 |       Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic) | 
 |           << Ptr->getType() << Ptr->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |     if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) || | 
 |         AtomTy.getAddressSpace() == LangAS::opencl_constant) { | 
 |       Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic) | 
 |           << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType() | 
 |           << Ptr->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |     ValType = AtomTy->castAs<AtomicType>()->getValueType(); | 
 |   } else if (Form != Load && Form != LoadCopy) { | 
 |     if (ValType.isConstQualified()) { | 
 |       Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer) | 
 |           << Ptr->getType() << Ptr->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |   } | 
 |  | 
 |   if (Form != TestAndSetByte && Form != ClearByte) { | 
 |     // Pointer to object of size zero is not allowed. | 
 |     if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy, | 
 |                             diag::err_incomplete_type)) | 
 |       return ExprError(); | 
 |  | 
 |     if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) { | 
 |       Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) | 
 |           << Ptr->getType() << 1 << Ptr->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |   } else { | 
 |     // The __atomic_clear and __atomic_test_and_set intrinsics accept any | 
 |     // non-const pointer type, including void* and pointers to incomplete | 
 |     // structs, but only access the first byte. | 
 |     AtomTy = Context.CharTy; | 
 |     AtomTy = AtomTy.withCVRQualifiers( | 
 |         pointerType->getPointeeType().getCVRQualifiers()); | 
 |     QualType PointerQT = Context.getPointerType(AtomTy); | 
 |     pointerType = PointerQT->getAs<PointerType>(); | 
 |     Ptr = ImpCastExprToType(Ptr, PointerQT, CK_BitCast).get(); | 
 |     ValType = AtomTy; | 
 |   } | 
 |  | 
 |   PointerAuthQualifier PointerAuth = AtomTy.getPointerAuth(); | 
 |   if (PointerAuth && PointerAuth.isAddressDiscriminated()) { | 
 |     Diag(ExprRange.getBegin(), | 
 |          diag::err_atomic_op_needs_non_address_discriminated_pointer) | 
 |         << 0 << Ptr->getType() << Ptr->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // For an arithmetic operation, the implied arithmetic must be well-formed. | 
 |   if (Form == Arithmetic) { | 
 |     // GCC does not enforce these rules for GNU atomics, but we do to help catch | 
 |     // trivial type errors. | 
 |     auto IsAllowedValueType = [&](QualType ValType, | 
 |                                   unsigned AllowedType) -> bool { | 
 |       if (ValType->isIntegerType()) | 
 |         return true; | 
 |       if (ValType->isPointerType()) | 
 |         return AllowedType & AOEVT_Pointer; | 
 |       if (!(ValType->isFloatingType() && (AllowedType & AOEVT_FP))) | 
 |         return false; | 
 |       // LLVM Parser does not allow atomicrmw with x86_fp80 type. | 
 |       if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) && | 
 |           &Context.getTargetInfo().getLongDoubleFormat() == | 
 |               &llvm::APFloat::x87DoubleExtended()) | 
 |         return false; | 
 |       return true; | 
 |     }; | 
 |     if (!IsAllowedValueType(ValType, ArithAllows)) { | 
 |       auto DID = ArithAllows & AOEVT_FP | 
 |                      ? (ArithAllows & AOEVT_Pointer | 
 |                             ? diag::err_atomic_op_needs_atomic_int_ptr_or_fp | 
 |                             : diag::err_atomic_op_needs_atomic_int_or_fp) | 
 |                      : diag::err_atomic_op_needs_atomic_int; | 
 |       Diag(ExprRange.getBegin(), DID) | 
 |           << IsC11 << Ptr->getType() << Ptr->getSourceRange(); | 
 |       return ExprError(); | 
 |     } | 
 |     if (IsC11 && ValType->isPointerType() && | 
 |         RequireCompleteType(Ptr->getBeginLoc(), ValType->getPointeeType(), | 
 |                             diag::err_incomplete_type)) { | 
 |       return ExprError(); | 
 |     } | 
 |   } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) { | 
 |     // For __atomic_*_n operations, the value type must be a scalar integral or | 
 |     // pointer type which is 1, 2, 4, 8 or 16 bytes in length. | 
 |     Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) | 
 |         << IsC11 << Ptr->getType() << Ptr->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context) && | 
 |       !AtomTy->isScalarType()) { | 
 |     // For GNU atomics, require a trivially-copyable type. This is not part of | 
 |     // the GNU atomics specification but we enforce it for consistency with | 
 |     // other atomics which generally all require a trivially-copyable type. This | 
 |     // is because atomics just copy bits. | 
 |     Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy) | 
 |         << Ptr->getType() << Ptr->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   switch (ValType.getObjCLifetime()) { | 
 |   case Qualifiers::OCL_None: | 
 |   case Qualifiers::OCL_ExplicitNone: | 
 |     // okay | 
 |     break; | 
 |  | 
 |   case Qualifiers::OCL_Weak: | 
 |   case Qualifiers::OCL_Strong: | 
 |   case Qualifiers::OCL_Autoreleasing: | 
 |     // FIXME: Can this happen? By this point, ValType should be known | 
 |     // to be trivially copyable. | 
 |     Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership) | 
 |         << ValType << Ptr->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // All atomic operations have an overload which takes a pointer to a volatile | 
 |   // 'A'.  We shouldn't let the volatile-ness of the pointee-type inject itself | 
 |   // into the result or the other operands. Similarly atomic_load takes a | 
 |   // pointer to a const 'A'. | 
 |   ValType.removeLocalVolatile(); | 
 |   ValType.removeLocalConst(); | 
 |   QualType ResultType = ValType; | 
 |   if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init || | 
 |       Form == ClearByte) | 
 |     ResultType = Context.VoidTy; | 
 |   else if (Form == C11CmpXchg || Form == GNUCmpXchg || Form == TestAndSetByte) | 
 |     ResultType = Context.BoolTy; | 
 |  | 
 |   // The type of a parameter passed 'by value'. In the GNU atomics, such | 
 |   // arguments are actually passed as pointers. | 
 |   QualType ByValType = ValType; // 'CP' | 
 |   bool IsPassedByAddress = false; | 
 |   if (!IsC11 && !IsHIP && !IsN) { | 
 |     ByValType = Ptr->getType(); | 
 |     IsPassedByAddress = true; | 
 |   } | 
 |  | 
 |   SmallVector<Expr *, 5> APIOrderedArgs; | 
 |   if (ArgOrder == Sema::AtomicArgumentOrder::AST) { | 
 |     APIOrderedArgs.push_back(Args[0]); | 
 |     switch (Form) { | 
 |     case Init: | 
 |     case Load: | 
 |       APIOrderedArgs.push_back(Args[1]); // Val1/Order | 
 |       break; | 
 |     case LoadCopy: | 
 |     case Copy: | 
 |     case Arithmetic: | 
 |     case Xchg: | 
 |       APIOrderedArgs.push_back(Args[2]); // Val1 | 
 |       APIOrderedArgs.push_back(Args[1]); // Order | 
 |       break; | 
 |     case GNUXchg: | 
 |       APIOrderedArgs.push_back(Args[2]); // Val1 | 
 |       APIOrderedArgs.push_back(Args[3]); // Val2 | 
 |       APIOrderedArgs.push_back(Args[1]); // Order | 
 |       break; | 
 |     case C11CmpXchg: | 
 |       APIOrderedArgs.push_back(Args[2]); // Val1 | 
 |       APIOrderedArgs.push_back(Args[4]); // Val2 | 
 |       APIOrderedArgs.push_back(Args[1]); // Order | 
 |       APIOrderedArgs.push_back(Args[3]); // OrderFail | 
 |       break; | 
 |     case GNUCmpXchg: | 
 |       APIOrderedArgs.push_back(Args[2]); // Val1 | 
 |       APIOrderedArgs.push_back(Args[4]); // Val2 | 
 |       APIOrderedArgs.push_back(Args[5]); // Weak | 
 |       APIOrderedArgs.push_back(Args[1]); // Order | 
 |       APIOrderedArgs.push_back(Args[3]); // OrderFail | 
 |       break; | 
 |     case TestAndSetByte: | 
 |     case ClearByte: | 
 |       APIOrderedArgs.push_back(Args[1]); // Order | 
 |       break; | 
 |     } | 
 |   } else | 
 |     APIOrderedArgs.append(Args.begin(), Args.end()); | 
 |  | 
 |   // The first argument's non-CV pointer type is used to deduce the type of | 
 |   // subsequent arguments, except for: | 
 |   //  - weak flag (always converted to bool) | 
 |   //  - memory order (always converted to int) | 
 |   //  - scope  (always converted to int) | 
 |   for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) { | 
 |     QualType Ty; | 
 |     if (i < NumVals[Form] + 1) { | 
 |       switch (i) { | 
 |       case 0: | 
 |         // The first argument is always a pointer. It has a fixed type. | 
 |         // It is always dereferenced, a nullptr is undefined. | 
 |         CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); | 
 |         // Nothing else to do: we already know all we want about this pointer. | 
 |         continue; | 
 |       case 1: | 
 |         // The second argument is the non-atomic operand. For arithmetic, this | 
 |         // is always passed by value, and for a compare_exchange it is always | 
 |         // passed by address. For the rest, GNU uses by-address and C11 uses | 
 |         // by-value. | 
 |         assert(Form != Load); | 
 |         if (Form == Arithmetic && ValType->isPointerType()) | 
 |           Ty = Context.getPointerDiffType(); | 
 |         else if (Form == Init || Form == Arithmetic) | 
 |           Ty = ValType; | 
 |         else if (Form == Copy || Form == Xchg) { | 
 |           if (IsPassedByAddress) { | 
 |             // The value pointer is always dereferenced, a nullptr is undefined. | 
 |             CheckNonNullArgument(*this, APIOrderedArgs[i], | 
 |                                  ExprRange.getBegin()); | 
 |           } | 
 |           Ty = ByValType; | 
 |         } else { | 
 |           Expr *ValArg = APIOrderedArgs[i]; | 
 |           // The value pointer is always dereferenced, a nullptr is undefined. | 
 |           CheckNonNullArgument(*this, ValArg, ExprRange.getBegin()); | 
 |           LangAS AS = LangAS::Default; | 
 |           // Keep address space of non-atomic pointer type. | 
 |           if (const PointerType *PtrTy = | 
 |                   ValArg->getType()->getAs<PointerType>()) { | 
 |             AS = PtrTy->getPointeeType().getAddressSpace(); | 
 |           } | 
 |           Ty = Context.getPointerType( | 
 |               Context.getAddrSpaceQualType(ValType.getUnqualifiedType(), AS)); | 
 |         } | 
 |         break; | 
 |       case 2: | 
 |         // The third argument to compare_exchange / GNU exchange is the desired | 
 |         // value, either by-value (for the C11 and *_n variant) or as a pointer. | 
 |         if (IsPassedByAddress) | 
 |           CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin()); | 
 |         Ty = ByValType; | 
 |         break; | 
 |       case 3: | 
 |         // The fourth argument to GNU compare_exchange is a 'weak' flag. | 
 |         Ty = Context.BoolTy; | 
 |         break; | 
 |       } | 
 |     } else { | 
 |       // The order(s) and scope are always converted to int. | 
 |       Ty = Context.IntTy; | 
 |     } | 
 |  | 
 |     InitializedEntity Entity = | 
 |         InitializedEntity::InitializeParameter(Context, Ty, false); | 
 |     ExprResult Arg = APIOrderedArgs[i]; | 
 |     Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); | 
 |     if (Arg.isInvalid()) | 
 |       return true; | 
 |     APIOrderedArgs[i] = Arg.get(); | 
 |   } | 
 |  | 
 |   // Permute the arguments into a 'consistent' order. | 
 |   SmallVector<Expr*, 5> SubExprs; | 
 |   SubExprs.push_back(Ptr); | 
 |   switch (Form) { | 
 |   case Init: | 
 |     // Note, AtomicExpr::getVal1() has a special case for this atomic. | 
 |     SubExprs.push_back(APIOrderedArgs[1]); // Val1 | 
 |     break; | 
 |   case Load: | 
 |   case TestAndSetByte: | 
 |   case ClearByte: | 
 |     SubExprs.push_back(APIOrderedArgs[1]); // Order | 
 |     break; | 
 |   case LoadCopy: | 
 |   case Copy: | 
 |   case Arithmetic: | 
 |   case Xchg: | 
 |     SubExprs.push_back(APIOrderedArgs[2]); // Order | 
 |     SubExprs.push_back(APIOrderedArgs[1]); // Val1 | 
 |     break; | 
 |   case GNUXchg: | 
 |     // Note, AtomicExpr::getVal2() has a special case for this atomic. | 
 |     SubExprs.push_back(APIOrderedArgs[3]); // Order | 
 |     SubExprs.push_back(APIOrderedArgs[1]); // Val1 | 
 |     SubExprs.push_back(APIOrderedArgs[2]); // Val2 | 
 |     break; | 
 |   case C11CmpXchg: | 
 |     SubExprs.push_back(APIOrderedArgs[3]); // Order | 
 |     SubExprs.push_back(APIOrderedArgs[1]); // Val1 | 
 |     SubExprs.push_back(APIOrderedArgs[4]); // OrderFail | 
 |     SubExprs.push_back(APIOrderedArgs[2]); // Val2 | 
 |     break; | 
 |   case GNUCmpXchg: | 
 |     SubExprs.push_back(APIOrderedArgs[4]); // Order | 
 |     SubExprs.push_back(APIOrderedArgs[1]); // Val1 | 
 |     SubExprs.push_back(APIOrderedArgs[5]); // OrderFail | 
 |     SubExprs.push_back(APIOrderedArgs[2]); // Val2 | 
 |     SubExprs.push_back(APIOrderedArgs[3]); // Weak | 
 |     break; | 
 |   } | 
 |  | 
 |   // If the memory orders are constants, check they are valid. | 
 |   if (SubExprs.size() >= 2 && Form != Init) { | 
 |     std::optional<llvm::APSInt> Success = | 
 |         SubExprs[1]->getIntegerConstantExpr(Context); | 
 |     if (Success && !isValidOrderingForOp(Success->getSExtValue(), Op)) { | 
 |       Diag(SubExprs[1]->getBeginLoc(), | 
 |            diag::warn_atomic_op_has_invalid_memory_order) | 
 |           << /*success=*/(Form == C11CmpXchg || Form == GNUCmpXchg) | 
 |           << SubExprs[1]->getSourceRange(); | 
 |     } | 
 |     if (SubExprs.size() >= 5) { | 
 |       if (std::optional<llvm::APSInt> Failure = | 
 |               SubExprs[3]->getIntegerConstantExpr(Context)) { | 
 |         if (!llvm::is_contained( | 
 |                 {llvm::AtomicOrderingCABI::relaxed, | 
 |                  llvm::AtomicOrderingCABI::consume, | 
 |                  llvm::AtomicOrderingCABI::acquire, | 
 |                  llvm::AtomicOrderingCABI::seq_cst}, | 
 |                 (llvm::AtomicOrderingCABI)Failure->getSExtValue())) { | 
 |           Diag(SubExprs[3]->getBeginLoc(), | 
 |                diag::warn_atomic_op_has_invalid_memory_order) | 
 |               << /*failure=*/2 << SubExprs[3]->getSourceRange(); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { | 
 |     auto *Scope = Args[Args.size() - 1]; | 
 |     if (std::optional<llvm::APSInt> Result = | 
 |             Scope->getIntegerConstantExpr(Context)) { | 
 |       if (!ScopeModel->isValid(Result->getZExtValue())) | 
 |         Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_sync_scope) | 
 |             << Scope->getSourceRange(); | 
 |     } | 
 |     SubExprs.push_back(Scope); | 
 |   } | 
 |  | 
 |   AtomicExpr *AE = new (Context) | 
 |       AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc); | 
 |  | 
 |   if ((Op == AtomicExpr::AO__c11_atomic_load || | 
 |        Op == AtomicExpr::AO__c11_atomic_store || | 
 |        Op == AtomicExpr::AO__opencl_atomic_load || | 
 |        Op == AtomicExpr::AO__hip_atomic_load || | 
 |        Op == AtomicExpr::AO__opencl_atomic_store || | 
 |        Op == AtomicExpr::AO__hip_atomic_store) && | 
 |       Context.AtomicUsesUnsupportedLibcall(AE)) | 
 |     Diag(AE->getBeginLoc(), diag::err_atomic_load_store_uses_lib) | 
 |         << ((Op == AtomicExpr::AO__c11_atomic_load || | 
 |              Op == AtomicExpr::AO__opencl_atomic_load || | 
 |              Op == AtomicExpr::AO__hip_atomic_load) | 
 |                 ? 0 | 
 |                 : 1); | 
 |  | 
 |   if (ValType->isBitIntType()) { | 
 |     Diag(Ptr->getExprLoc(), diag::err_atomic_builtin_bit_int_prohibit); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   return AE; | 
 | } | 
 |  | 
 | /// checkBuiltinArgument - Given a call to a builtin function, perform | 
 | /// normal type-checking on the given argument, updating the call in | 
 | /// place.  This is useful when a builtin function requires custom | 
 | /// type-checking for some of its arguments but not necessarily all of | 
 | /// them. | 
 | /// | 
 | /// Returns true on error. | 
 | static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { | 
 |   FunctionDecl *Fn = E->getDirectCallee(); | 
 |   assert(Fn && "builtin call without direct callee!"); | 
 |  | 
 |   ParmVarDecl *Param = Fn->getParamDecl(ArgIndex); | 
 |   InitializedEntity Entity = | 
 |     InitializedEntity::InitializeParameter(S.Context, Param); | 
 |  | 
 |   ExprResult Arg = E->getArg(ArgIndex); | 
 |   Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); | 
 |   if (Arg.isInvalid()) | 
 |     return true; | 
 |  | 
 |   E->setArg(ArgIndex, Arg.get()); | 
 |   return false; | 
 | } | 
 |  | 
 | ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { | 
 |   CallExpr *TheCall = static_cast<CallExpr *>(TheCallResult.get()); | 
 |   Expr *Callee = TheCall->getCallee(); | 
 |   DeclRefExpr *DRE = cast<DeclRefExpr>(Callee->IgnoreParenCasts()); | 
 |   FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); | 
 |  | 
 |   // Ensure that we have at least one argument to do type inference from. | 
 |   if (TheCall->getNumArgs() < 1) { | 
 |     Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) | 
 |         << 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0 | 
 |         << Callee->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // Inspect the first argument of the atomic builtin.  This should always be | 
 |   // a pointer type, whose element is an integral scalar or pointer type. | 
 |   // Because it is a pointer type, we don't have to worry about any implicit | 
 |   // casts here. | 
 |   // FIXME: We don't allow floating point scalars as input. | 
 |   Expr *FirstArg = TheCall->getArg(0); | 
 |   ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg); | 
 |   if (FirstArgResult.isInvalid()) | 
 |     return ExprError(); | 
 |   FirstArg = FirstArgResult.get(); | 
 |   TheCall->setArg(0, FirstArg); | 
 |  | 
 |   const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>(); | 
 |   if (!pointerType) { | 
 |     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) | 
 |         << FirstArg->getType() << 0 << FirstArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   QualType ValType = pointerType->getPointeeType(); | 
 |   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && | 
 |       !ValType->isBlockPointerType()) { | 
 |     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr) | 
 |         << FirstArg->getType() << 0 << FirstArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |   PointerAuthQualifier PointerAuth = ValType.getPointerAuth(); | 
 |   if (PointerAuth && PointerAuth.isAddressDiscriminated()) { | 
 |     Diag(FirstArg->getBeginLoc(), | 
 |          diag::err_atomic_op_needs_non_address_discriminated_pointer) | 
 |         << 1 << ValType << FirstArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   if (ValType.isConstQualified()) { | 
 |     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_cannot_be_const) | 
 |         << FirstArg->getType() << FirstArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   switch (ValType.getObjCLifetime()) { | 
 |   case Qualifiers::OCL_None: | 
 |   case Qualifiers::OCL_ExplicitNone: | 
 |     // okay | 
 |     break; | 
 |  | 
 |   case Qualifiers::OCL_Weak: | 
 |   case Qualifiers::OCL_Strong: | 
 |   case Qualifiers::OCL_Autoreleasing: | 
 |     Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) | 
 |         << ValType << FirstArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // Strip any qualifiers off ValType. | 
 |   ValType = ValType.getUnqualifiedType(); | 
 |  | 
 |   // The majority of builtins return a value, but a few have special return | 
 |   // types, so allow them to override appropriately below. | 
 |   QualType ResultType = ValType; | 
 |  | 
 |   // We need to figure out which concrete builtin this maps onto.  For example, | 
 |   // __sync_fetch_and_add with a 2 byte object turns into | 
 |   // __sync_fetch_and_add_2. | 
 | #define BUILTIN_ROW(x) \ | 
 |   { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \ | 
 |     Builtin::BI##x##_8, Builtin::BI##x##_16 } | 
 |  | 
 |   static const unsigned BuiltinIndices[][5] = { | 
 |     BUILTIN_ROW(__sync_fetch_and_add), | 
 |     BUILTIN_ROW(__sync_fetch_and_sub), | 
 |     BUILTIN_ROW(__sync_fetch_and_or), | 
 |     BUILTIN_ROW(__sync_fetch_and_and), | 
 |     BUILTIN_ROW(__sync_fetch_and_xor), | 
 |     BUILTIN_ROW(__sync_fetch_and_nand), | 
 |  | 
 |     BUILTIN_ROW(__sync_add_and_fetch), | 
 |     BUILTIN_ROW(__sync_sub_and_fetch), | 
 |     BUILTIN_ROW(__sync_and_and_fetch), | 
 |     BUILTIN_ROW(__sync_or_and_fetch), | 
 |     BUILTIN_ROW(__sync_xor_and_fetch), | 
 |     BUILTIN_ROW(__sync_nand_and_fetch), | 
 |  | 
 |     BUILTIN_ROW(__sync_val_compare_and_swap), | 
 |     BUILTIN_ROW(__sync_bool_compare_and_swap), | 
 |     BUILTIN_ROW(__sync_lock_test_and_set), | 
 |     BUILTIN_ROW(__sync_lock_release), | 
 |     BUILTIN_ROW(__sync_swap) | 
 |   }; | 
 | #undef BUILTIN_ROW | 
 |  | 
 |   // Determine the index of the size. | 
 |   unsigned SizeIndex; | 
 |   switch (Context.getTypeSizeInChars(ValType).getQuantity()) { | 
 |   case 1: SizeIndex = 0; break; | 
 |   case 2: SizeIndex = 1; break; | 
 |   case 4: SizeIndex = 2; break; | 
 |   case 8: SizeIndex = 3; break; | 
 |   case 16: SizeIndex = 4; break; | 
 |   default: | 
 |     Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_pointer_size) | 
 |         << FirstArg->getType() << FirstArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // Each of these builtins has one pointer argument, followed by some number of | 
 |   // values (0, 1 or 2) followed by a potentially empty varags list of stuff | 
 |   // that we ignore.  Find out which row of BuiltinIndices to read from as well | 
 |   // as the number of fixed args. | 
 |   unsigned BuiltinID = FDecl->getBuiltinID(); | 
 |   unsigned BuiltinIndex, NumFixed = 1; | 
 |   bool WarnAboutSemanticsChange = false; | 
 |   switch (BuiltinID) { | 
 |   default: llvm_unreachable("Unknown overloaded atomic builtin!"); | 
 |   case Builtin::BI__sync_fetch_and_add: | 
 |   case Builtin::BI__sync_fetch_and_add_1: | 
 |   case Builtin::BI__sync_fetch_and_add_2: | 
 |   case Builtin::BI__sync_fetch_and_add_4: | 
 |   case Builtin::BI__sync_fetch_and_add_8: | 
 |   case Builtin::BI__sync_fetch_and_add_16: | 
 |     BuiltinIndex = 0; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_fetch_and_sub: | 
 |   case Builtin::BI__sync_fetch_and_sub_1: | 
 |   case Builtin::BI__sync_fetch_and_sub_2: | 
 |   case Builtin::BI__sync_fetch_and_sub_4: | 
 |   case Builtin::BI__sync_fetch_and_sub_8: | 
 |   case Builtin::BI__sync_fetch_and_sub_16: | 
 |     BuiltinIndex = 1; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_fetch_and_or: | 
 |   case Builtin::BI__sync_fetch_and_or_1: | 
 |   case Builtin::BI__sync_fetch_and_or_2: | 
 |   case Builtin::BI__sync_fetch_and_or_4: | 
 |   case Builtin::BI__sync_fetch_and_or_8: | 
 |   case Builtin::BI__sync_fetch_and_or_16: | 
 |     BuiltinIndex = 2; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_fetch_and_and: | 
 |   case Builtin::BI__sync_fetch_and_and_1: | 
 |   case Builtin::BI__sync_fetch_and_and_2: | 
 |   case Builtin::BI__sync_fetch_and_and_4: | 
 |   case Builtin::BI__sync_fetch_and_and_8: | 
 |   case Builtin::BI__sync_fetch_and_and_16: | 
 |     BuiltinIndex = 3; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_fetch_and_xor: | 
 |   case Builtin::BI__sync_fetch_and_xor_1: | 
 |   case Builtin::BI__sync_fetch_and_xor_2: | 
 |   case Builtin::BI__sync_fetch_and_xor_4: | 
 |   case Builtin::BI__sync_fetch_and_xor_8: | 
 |   case Builtin::BI__sync_fetch_and_xor_16: | 
 |     BuiltinIndex = 4; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_fetch_and_nand: | 
 |   case Builtin::BI__sync_fetch_and_nand_1: | 
 |   case Builtin::BI__sync_fetch_and_nand_2: | 
 |   case Builtin::BI__sync_fetch_and_nand_4: | 
 |   case Builtin::BI__sync_fetch_and_nand_8: | 
 |   case Builtin::BI__sync_fetch_and_nand_16: | 
 |     BuiltinIndex = 5; | 
 |     WarnAboutSemanticsChange = true; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_add_and_fetch: | 
 |   case Builtin::BI__sync_add_and_fetch_1: | 
 |   case Builtin::BI__sync_add_and_fetch_2: | 
 |   case Builtin::BI__sync_add_and_fetch_4: | 
 |   case Builtin::BI__sync_add_and_fetch_8: | 
 |   case Builtin::BI__sync_add_and_fetch_16: | 
 |     BuiltinIndex = 6; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_sub_and_fetch: | 
 |   case Builtin::BI__sync_sub_and_fetch_1: | 
 |   case Builtin::BI__sync_sub_and_fetch_2: | 
 |   case Builtin::BI__sync_sub_and_fetch_4: | 
 |   case Builtin::BI__sync_sub_and_fetch_8: | 
 |   case Builtin::BI__sync_sub_and_fetch_16: | 
 |     BuiltinIndex = 7; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_and_and_fetch: | 
 |   case Builtin::BI__sync_and_and_fetch_1: | 
 |   case Builtin::BI__sync_and_and_fetch_2: | 
 |   case Builtin::BI__sync_and_and_fetch_4: | 
 |   case Builtin::BI__sync_and_and_fetch_8: | 
 |   case Builtin::BI__sync_and_and_fetch_16: | 
 |     BuiltinIndex = 8; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_or_and_fetch: | 
 |   case Builtin::BI__sync_or_and_fetch_1: | 
 |   case Builtin::BI__sync_or_and_fetch_2: | 
 |   case Builtin::BI__sync_or_and_fetch_4: | 
 |   case Builtin::BI__sync_or_and_fetch_8: | 
 |   case Builtin::BI__sync_or_and_fetch_16: | 
 |     BuiltinIndex = 9; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_xor_and_fetch: | 
 |   case Builtin::BI__sync_xor_and_fetch_1: | 
 |   case Builtin::BI__sync_xor_and_fetch_2: | 
 |   case Builtin::BI__sync_xor_and_fetch_4: | 
 |   case Builtin::BI__sync_xor_and_fetch_8: | 
 |   case Builtin::BI__sync_xor_and_fetch_16: | 
 |     BuiltinIndex = 10; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_nand_and_fetch: | 
 |   case Builtin::BI__sync_nand_and_fetch_1: | 
 |   case Builtin::BI__sync_nand_and_fetch_2: | 
 |   case Builtin::BI__sync_nand_and_fetch_4: | 
 |   case Builtin::BI__sync_nand_and_fetch_8: | 
 |   case Builtin::BI__sync_nand_and_fetch_16: | 
 |     BuiltinIndex = 11; | 
 |     WarnAboutSemanticsChange = true; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_val_compare_and_swap: | 
 |   case Builtin::BI__sync_val_compare_and_swap_1: | 
 |   case Builtin::BI__sync_val_compare_and_swap_2: | 
 |   case Builtin::BI__sync_val_compare_and_swap_4: | 
 |   case Builtin::BI__sync_val_compare_and_swap_8: | 
 |   case Builtin::BI__sync_val_compare_and_swap_16: | 
 |     BuiltinIndex = 12; | 
 |     NumFixed = 2; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_bool_compare_and_swap: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_1: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_2: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_4: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_8: | 
 |   case Builtin::BI__sync_bool_compare_and_swap_16: | 
 |     BuiltinIndex = 13; | 
 |     NumFixed = 2; | 
 |     ResultType = Context.BoolTy; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_lock_test_and_set: | 
 |   case Builtin::BI__sync_lock_test_and_set_1: | 
 |   case Builtin::BI__sync_lock_test_and_set_2: | 
 |   case Builtin::BI__sync_lock_test_and_set_4: | 
 |   case Builtin::BI__sync_lock_test_and_set_8: | 
 |   case Builtin::BI__sync_lock_test_and_set_16: | 
 |     BuiltinIndex = 14; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_lock_release: | 
 |   case Builtin::BI__sync_lock_release_1: | 
 |   case Builtin::BI__sync_lock_release_2: | 
 |   case Builtin::BI__sync_lock_release_4: | 
 |   case Builtin::BI__sync_lock_release_8: | 
 |   case Builtin::BI__sync_lock_release_16: | 
 |     BuiltinIndex = 15; | 
 |     NumFixed = 0; | 
 |     ResultType = Context.VoidTy; | 
 |     break; | 
 |  | 
 |   case Builtin::BI__sync_swap: | 
 |   case Builtin::BI__sync_swap_1: | 
 |   case Builtin::BI__sync_swap_2: | 
 |   case Builtin::BI__sync_swap_4: | 
 |   case Builtin::BI__sync_swap_8: | 
 |   case Builtin::BI__sync_swap_16: | 
 |     BuiltinIndex = 16; | 
 |     break; | 
 |   } | 
 |  | 
 |   // Now that we know how many fixed arguments we expect, first check that we | 
 |   // have at least that many. | 
 |   if (TheCall->getNumArgs() < 1+NumFixed) { | 
 |     Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) | 
 |         << 0 << 1 + NumFixed << TheCall->getNumArgs() << /*is non object*/ 0 | 
 |         << Callee->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   Diag(TheCall->getEndLoc(), diag::warn_atomic_implicit_seq_cst) | 
 |       << Callee->getSourceRange(); | 
 |  | 
 |   if (WarnAboutSemanticsChange) { | 
 |     Diag(TheCall->getEndLoc(), diag::warn_sync_fetch_and_nand_semantics_change) | 
 |         << Callee->getSourceRange(); | 
 |   } | 
 |  | 
 |   // Get the decl for the concrete builtin from this, we can tell what the | 
 |   // concrete integer type we should convert to is. | 
 |   unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; | 
 |   std::string NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID); | 
 |   FunctionDecl *NewBuiltinDecl; | 
 |   if (NewBuiltinID == BuiltinID) | 
 |     NewBuiltinDecl = FDecl; | 
 |   else { | 
 |     // Perform builtin lookup to avoid redeclaring it. | 
 |     DeclarationName DN(&Context.Idents.get(NewBuiltinName)); | 
 |     LookupResult Res(*this, DN, DRE->getBeginLoc(), LookupOrdinaryName); | 
 |     LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true); | 
 |     assert(Res.getFoundDecl()); | 
 |     NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl()); | 
 |     if (!NewBuiltinDecl) | 
 |       return ExprError(); | 
 |   } | 
 |  | 
 |   // The first argument --- the pointer --- has a fixed type; we | 
 |   // deduce the types of the rest of the arguments accordingly.  Walk | 
 |   // the remaining arguments, converting them to the deduced value type. | 
 |   for (unsigned i = 0; i != NumFixed; ++i) { | 
 |     ExprResult Arg = TheCall->getArg(i+1); | 
 |  | 
 |     // GCC does an implicit conversion to the pointer or integer ValType.  This | 
 |     // can fail in some cases (1i -> int**), check for this error case now. | 
 |     // Initialize the argument. | 
 |     InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, | 
 |                                                    ValType, /*consume*/ false); | 
 |     Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); | 
 |     if (Arg.isInvalid()) | 
 |       return ExprError(); | 
 |  | 
 |     // Okay, we have something that *can* be converted to the right type.  Check | 
 |     // to see if there is a potentially weird extension going on here.  This can | 
 |     // happen when you do an atomic operation on something like an char* and | 
 |     // pass in 42.  The 42 gets converted to char.  This is even more strange | 
 |     // for things like 45.123 -> char, etc. | 
 |     // FIXME: Do this check. | 
 |     TheCall->setArg(i+1, Arg.get()); | 
 |   } | 
 |  | 
 |   // Create a new DeclRefExpr to refer to the new decl. | 
 |   DeclRefExpr *NewDRE = DeclRefExpr::Create( | 
 |       Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl, | 
 |       /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy, | 
 |       DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse()); | 
 |  | 
 |   // Set the callee in the CallExpr. | 
 |   // FIXME: This loses syntactic information. | 
 |   QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType()); | 
 |   ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy, | 
 |                                               CK_BuiltinFnToFnPtr); | 
 |   TheCall->setCallee(PromotedCall.get()); | 
 |  | 
 |   // Change the result type of the call to match the original value type. This | 
 |   // is arbitrary, but the codegen for these builtins ins design to handle it | 
 |   // gracefully. | 
 |   TheCall->setType(ResultType); | 
 |  | 
 |   // Prohibit problematic uses of bit-precise integer types with atomic | 
 |   // builtins. The arguments would have already been converted to the first | 
 |   // argument's type, so only need to check the first argument. | 
 |   const auto *BitIntValType = ValType->getAs<BitIntType>(); | 
 |   if (BitIntValType && !llvm::isPowerOf2_64(BitIntValType->getNumBits())) { | 
 |     Diag(FirstArg->getExprLoc(), diag::err_atomic_builtin_ext_int_size); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   return TheCallResult; | 
 | } | 
 |  | 
 | ExprResult Sema::BuiltinNontemporalOverloaded(ExprResult TheCallResult) { | 
 |   CallExpr *TheCall = (CallExpr *)TheCallResult.get(); | 
 |   DeclRefExpr *DRE = | 
 |       cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); | 
 |   FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); | 
 |   unsigned BuiltinID = FDecl->getBuiltinID(); | 
 |   assert((BuiltinID == Builtin::BI__builtin_nontemporal_store || | 
 |           BuiltinID == Builtin::BI__builtin_nontemporal_load) && | 
 |          "Unexpected nontemporal load/store builtin!"); | 
 |   bool isStore = BuiltinID == Builtin::BI__builtin_nontemporal_store; | 
 |   unsigned numArgs = isStore ? 2 : 1; | 
 |  | 
 |   // Ensure that we have the proper number of arguments. | 
 |   if (checkArgCount(TheCall, numArgs)) | 
 |     return ExprError(); | 
 |  | 
 |   // Inspect the last argument of the nontemporal builtin.  This should always | 
 |   // be a pointer type, from which we imply the type of the memory access. | 
 |   // Because it is a pointer type, we don't have to worry about any implicit | 
 |   // casts here. | 
 |   Expr *PointerArg = TheCall->getArg(numArgs - 1); | 
 |   ExprResult PointerArgResult = | 
 |       DefaultFunctionArrayLvalueConversion(PointerArg); | 
 |  | 
 |   if (PointerArgResult.isInvalid()) | 
 |     return ExprError(); | 
 |   PointerArg = PointerArgResult.get(); | 
 |   TheCall->setArg(numArgs - 1, PointerArg); | 
 |  | 
 |   const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>(); | 
 |   if (!pointerType) { | 
 |     Diag(DRE->getBeginLoc(), diag::err_nontemporal_builtin_must_be_pointer) | 
 |         << PointerArg->getType() << PointerArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   QualType ValType = pointerType->getPointeeType(); | 
 |  | 
 |   // Strip any qualifiers off ValType. | 
 |   ValType = ValType.getUnqualifiedType(); | 
 |   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && | 
 |       !ValType->isBlockPointerType() && !ValType->isFloatingType() && | 
 |       !ValType->isVectorType()) { | 
 |     Diag(DRE->getBeginLoc(), | 
 |          diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector) | 
 |         << PointerArg->getType() << PointerArg->getSourceRange(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   if (!isStore) { | 
 |     TheCall->setType(ValType); | 
 |     return TheCallResult; | 
 |   } | 
 |  | 
 |   ExprResult ValArg = TheCall->getArg(0); | 
 |   InitializedEntity Entity = InitializedEntity::InitializeParameter( | 
 |       Context, ValType, /*consume*/ false); | 
 |   ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); | 
 |   if (ValArg.isInvalid()) | 
 |     return ExprError(); | 
 |  | 
 |   TheCall->setArg(0, ValArg.get()); | 
 |   TheCall->setType(Context.VoidTy); | 
 |   return TheCallResult; | 
 | } | 
 |  | 
 | /// CheckObjCString - Checks that the format string argument to the os_log() | 
 | /// and os_trace() functions is correct, and converts it to const char *. | 
 | ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { | 
 |   Arg = Arg->IgnoreParenCasts(); | 
 |   auto *Literal = dyn_cast<StringLiteral>(Arg); | 
 |   if (!Literal) { | 
 |     if (auto *ObjcLiteral = dyn_cast<ObjCStringLiteral>(Arg)) { | 
 |       Literal = ObjcLiteral->getString(); | 
 |     } | 
 |   } | 
 |  | 
 |   if (!Literal || (!Literal->isOrdinary() && !Literal->isUTF8())) { | 
 |     return ExprError( | 
 |         Diag(Arg->getBeginLoc(), diag::err_os_log_format_not_string_constant) | 
 |         << Arg->getSourceRange()); | 
 |   } | 
 |  | 
 |   ExprResult Result(Literal); | 
 |   QualType ResultTy = Context.getPointerType(Context.CharTy.withConst()); | 
 |   InitializedEntity Entity = | 
 |       InitializedEntity::InitializeParameter(Context, ResultTy, false); | 
 |   Result = PerformCopyInitialization(Entity, SourceLocation(), Result); | 
 |   return Result; | 
 | } | 
 |  | 
 | /// Check that the user is calling the appropriate va_start builtin for the | 
 | /// target and calling convention. | 
 | static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { | 
 |   const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); | 
 |   bool IsX64 = TT.getArch() == llvm::Triple::x86_64; | 
 |   bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 || | 
 |                     TT.getArch() == llvm::Triple::aarch64_32); | 
 |   bool IsWindowsOrUEFI = TT.isOSWindows() || TT.isUEFI(); | 
 |   bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; | 
 |   if (IsX64 || IsAArch64) { | 
 |     CallingConv CC = CC_C; | 
 |     if (const FunctionDecl *FD = S.getCurFunctionDecl()) | 
 |       CC = FD->getType()->castAs<FunctionType>()->getCallConv(); | 
 |     if (IsMSVAStart) { | 
 |       // Don't allow this in System V ABI functions. | 
 |       if (CC == CC_X86_64SysV || (!IsWindowsOrUEFI && CC != CC_Win64)) | 
 |         return S.Diag(Fn->getBeginLoc(), | 
 |                       diag::err_ms_va_start_used_in_sysv_function); | 
 |     } else { | 
 |       // On x86-64/AArch64 Unix, don't allow this in Win64 ABI functions. | 
 |       // On x64 Windows, don't allow this in System V ABI functions. | 
 |       // (Yes, that means there's no corresponding way to support variadic | 
 |       // System V ABI functions on Windows.) | 
 |       if ((IsWindowsOrUEFI && CC == CC_X86_64SysV) || | 
 |           (!IsWindowsOrUEFI && CC == CC_Win64)) | 
 |         return S.Diag(Fn->getBeginLoc(), | 
 |                       diag::err_va_start_used_in_wrong_abi_function) | 
 |                << !IsWindowsOrUEFI; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (IsMSVAStart) | 
 |     return S.Diag(Fn->getBeginLoc(), diag::err_builtin_x64_aarch64_only); | 
 |   return false; | 
 | } | 
 |  | 
 | static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn, | 
 |                                              ParmVarDecl **LastParam = nullptr) { | 
 |   // Determine whether the current function, block, or obj-c method is variadic | 
 |   // and get its parameter list. | 
 |   bool IsVariadic = false; | 
 |   ArrayRef<ParmVarDecl *> Params; | 
 |   DeclContext *Caller = S.CurContext; | 
 |   if (auto *Block = dyn_cast<BlockDecl>(Caller)) { | 
 |     IsVariadic = Block->isVariadic(); | 
 |     Params = Block->parameters(); | 
 |   } else if (auto *FD = dyn_cast<FunctionDecl>(Caller)) { | 
 |     IsVariadic = FD->isVariadic(); | 
 |     Params = FD->parameters(); | 
 |   } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Caller)) { | 
 |     IsVariadic = MD->isVariadic(); | 
 |     // FIXME: This isn't correct for methods (results in bogus warning). | 
 |     Params = MD->parameters(); | 
 |   } else if (isa<CapturedDecl>(Caller)) { | 
 |     // We don't support va_start in a CapturedDecl. | 
 |     S.Diag(Fn->getBeginLoc(), diag::err_va_start_captured_stmt); | 
 |     return true; | 
 |   } else { | 
 |     // This must be some other declcontext that parses exprs. | 
 |     S.Diag(Fn->getBeginLoc(), diag::err_va_start_outside_function); | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (!IsVariadic) { | 
 |     S.Diag(Fn->getBeginLoc(), diag::err_va_start_fixed_function); | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (LastParam) | 
 |     *LastParam = Params.empty() ? nullptr : Params.back(); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { | 
 |   Expr *Fn = TheCall->getCallee(); | 
 |   if (checkVAStartABI(*this, BuiltinID, Fn)) | 
 |     return true; | 
 |  | 
 |   if (BuiltinID == Builtin::BI__builtin_c23_va_start) { | 
 |     // This builtin requires one argument (the va_list), allows two arguments, | 
 |     // but diagnoses more than two arguments. e.g., | 
 |     //   __builtin_c23_va_start(); // error | 
 |     //   __builtin_c23_va_start(list); // ok | 
 |     //   __builtin_c23_va_start(list, param); // ok | 
 |     //   __builtin_c23_va_start(list, anything, anything); // error | 
 |     // This differs from the GCC behavior in that they accept the last case | 
 |     // with a warning, but it doesn't seem like a useful behavior to allow. | 
 |     if (checkArgCountRange(TheCall, 1, 2)) | 
 |       return true; | 
 |   } else { | 
 |     // In C23 mode, va_start only needs one argument. However, the builtin still | 
 |     // requires two arguments (which matches the behavior of the GCC builtin), | 
 |     // <stdarg.h> passes `0` as the second argument in C23 mode. | 
 |     if (checkArgCount(TheCall, 2)) | 
 |       return true; | 
 |   } | 
 |  | 
 |   // Type-check the first argument normally. | 
 |   if (checkBuiltinArgument(*this, TheCall, 0)) | 
 |     return true; | 
 |  | 
 |   // Check that the current function is variadic, and get its last parameter. | 
 |   ParmVarDecl *LastParam; | 
 |   if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam)) | 
 |     return true; | 
 |  | 
 |   // Verify that the second argument to the builtin is the last non-variadic | 
 |   // argument of the current function or method. In C23 mode, if the call is | 
 |   // not to __builtin_c23_va_start, and the second argument is an integer | 
 |   // constant expression with value 0, then we don't bother with this check. | 
 |   // For __builtin_c23_va_start, we only perform the check for the second | 
 |   // argument being the last argument to the current function if there is a | 
 |   // second argument present. | 
 |   if (BuiltinID == Builtin::BI__builtin_c23_va_start && | 
 |       TheCall->getNumArgs() < 2) { | 
 |     Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg); | 
 |     return false; | 
 |   } | 
 |  | 
 |   const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); | 
 |   if (std::optional<llvm::APSInt> Val = | 
 |           TheCall->getArg(1)->getIntegerConstantExpr(Context); | 
 |       Val && LangOpts.C23 && *Val == 0 && | 
 |       BuiltinID != Builtin::BI__builtin_c23_va_start) { | 
 |     Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg); | 
 |     return false; | 
 |   } | 
 |  | 
 |   // These are valid if SecondArgIsLastNonVariadicArgument is false after the | 
 |   // next block. | 
 |   QualType Type; | 
 |   SourceLocation ParamLoc; | 
 |   bool IsCRegister = false; | 
 |   bool SecondArgIsLastNonVariadicArgument = false; | 
 |   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) { | 
 |     if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) { | 
 |       SecondArgIsLastNonVariadicArgument = PV == LastParam; | 
 |  | 
 |       Type = PV->getType(); | 
 |       ParamLoc = PV->getLocation(); | 
 |       IsCRegister = | 
 |           PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus; | 
 |     } | 
 |   } | 
 |  | 
 |   if (!SecondArgIsLastNonVariadicArgument) | 
 |     Diag(TheCall->getArg(1)->getBeginLoc(), | 
 |          diag::warn_second_arg_of_va_start_not_last_non_variadic_param); | 
 |   else if (IsCRegister || Type->isReferenceType() || | 
 |            Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { | 
 |              // Promotable integers are UB, but enumerations need a bit of | 
 |              // extra checking to see what their promotable type actually is. | 
 |              if (!Context.isPromotableIntegerType(Type)) | 
 |                return false; | 
 |              const auto *ED = Type->getAsEnumDecl(); | 
 |              if (!ED) | 
 |                return true; | 
 |              return !Context.typesAreCompatible(ED->getPromotionType(), Type); | 
 |            }()) { | 
 |     unsigned Reason = 0; | 
 |     if (Type->isReferenceType())  Reason = 1; | 
 |     else if (IsCRegister)         Reason = 2; | 
 |     Diag(Arg->getBeginLoc(), diag::warn_va_start_type_is_undefined) << Reason; | 
 |     Diag(ParamLoc, diag::note_parameter_type) << Type; | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinVAStartARMMicrosoft(CallExpr *Call) { | 
 |   auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool { | 
 |     const LangOptions &LO = getLangOpts(); | 
 |  | 
 |     if (LO.CPlusPlus) | 
 |       return Arg->getType() | 
 |                  .getCanonicalType() | 
 |                  .getTypePtr() | 
 |                  ->getPointeeType() | 
 |                  .withoutLocalFastQualifiers() == Context.CharTy; | 
 |  | 
 |     // In C, allow aliasing through `char *`, this is required for AArch64 at | 
 |     // least. | 
 |     return true; | 
 |   }; | 
 |  | 
 |   // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, | 
 |   //                 const char *named_addr); | 
 |  | 
 |   Expr *Func = Call->getCallee(); | 
 |  | 
 |   if (Call->getNumArgs() < 3) | 
 |     return Diag(Call->getEndLoc(), | 
 |                 diag::err_typecheck_call_too_few_args_at_least) | 
 |            << 0 /*function call*/ << 3 << Call->getNumArgs() | 
 |            << /*is non object*/ 0; | 
 |  | 
 |   // Type-check the first argument normally. | 
 |   if (checkBuiltinArgument(*this, Call, 0)) | 
 |     return true; | 
 |  | 
 |   // Check that the current function is variadic. | 
 |   if (checkVAStartIsInVariadicFunction(*this, Func)) | 
 |     return true; | 
 |  | 
 |   // __va_start on Windows does not validate the parameter qualifiers | 
 |  | 
 |   const Expr *Arg1 = Call->getArg(1)->IgnoreParens(); | 
 |   const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr(); | 
 |  | 
 |   const Expr *Arg2 = Call->getArg(2)->IgnoreParens(); | 
 |   const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr(); | 
 |  | 
 |   const QualType &ConstCharPtrTy = | 
 |       Context.getPointerType(Context.CharTy.withConst()); | 
 |   if (!Arg1Ty->isPointerType() || !IsSuitablyTypedFormatArgument(Arg1)) | 
 |     Diag(Arg1->getBeginLoc(), diag::err_typecheck_convert_incompatible) | 
 |         << Arg1->getType() << ConstCharPtrTy << 1 /* different class */ | 
 |         << 0                                      /* qualifier difference */ | 
 |         << 3                                      /* parameter mismatch */ | 
 |         << 2 << Arg1->getType() << ConstCharPtrTy; | 
 |  | 
 |   const QualType SizeTy = Context.getSizeType(); | 
 |   if (!Context.hasSameType( | 
 |           Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers(), | 
 |           SizeTy)) | 
 |     Diag(Arg2->getBeginLoc(), diag::err_typecheck_convert_incompatible) | 
 |         << Arg2->getType() << SizeTy << 1 /* different class */ | 
 |         << 0                              /* qualifier difference */ | 
 |         << 3                              /* parameter mismatch */ | 
 |         << 3 << Arg2->getType() << SizeTy; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { | 
 |   if (checkArgCount(TheCall, 2)) | 
 |     return true; | 
 |  | 
 |   if (BuiltinID == Builtin::BI__builtin_isunordered && | 
 |       TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs()) | 
 |     Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | 
 |         << 1 << 0 << TheCall->getSourceRange(); | 
 |  | 
 |   ExprResult OrigArg0 = TheCall->getArg(0); | 
 |   ExprResult OrigArg1 = TheCall->getArg(1); | 
 |  | 
 |   // Do standard promotions between the two arguments, returning their common | 
 |   // type. | 
 |   QualType Res = UsualArithmeticConversions( | 
 |       OrigArg0, OrigArg1, TheCall->getExprLoc(), ArithConvKind::Comparison); | 
 |   if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) | 
 |     return true; | 
 |  | 
 |   // Make sure any conversions are pushed back into the call; this is | 
 |   // type safe since unordered compare builtins are declared as "_Bool | 
 |   // foo(...)". | 
 |   TheCall->setArg(0, OrigArg0.get()); | 
 |   TheCall->setArg(1, OrigArg1.get()); | 
 |  | 
 |   if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent()) | 
 |     return false; | 
 |  | 
 |   // If the common type isn't a real floating type, then the arguments were | 
 |   // invalid for this operation. | 
 |   if (Res.isNull() || !Res->isRealFloatingType()) | 
 |     return Diag(OrigArg0.get()->getBeginLoc(), | 
 |                 diag::err_typecheck_call_invalid_ordered_compare) | 
 |            << OrigArg0.get()->getType() << OrigArg1.get()->getType() | 
 |            << SourceRange(OrigArg0.get()->getBeginLoc(), | 
 |                           OrigArg1.get()->getEndLoc()); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, | 
 |                                    unsigned BuiltinID) { | 
 |   if (checkArgCount(TheCall, NumArgs)) | 
 |     return true; | 
 |  | 
 |   FPOptions FPO = TheCall->getFPFeaturesInEffect(getLangOpts()); | 
 |   if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite || | 
 |                                BuiltinID == Builtin::BI__builtin_isinf || | 
 |                                BuiltinID == Builtin::BI__builtin_isinf_sign)) | 
 |     Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | 
 |         << 0 << 0 << TheCall->getSourceRange(); | 
 |  | 
 |   if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan || | 
 |                                BuiltinID == Builtin::BI__builtin_isunordered)) | 
 |     Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | 
 |         << 1 << 0 << TheCall->getSourceRange(); | 
 |  | 
 |   bool IsFPClass = NumArgs == 2; | 
 |  | 
 |   // Find out position of floating-point argument. | 
 |   unsigned FPArgNo = IsFPClass ? 0 : NumArgs - 1; | 
 |  | 
 |   // We can count on all parameters preceding the floating-point just being int. | 
 |   // Try all of those. | 
 |   for (unsigned i = 0; i < FPArgNo; ++i) { | 
 |     Expr *Arg = TheCall->getArg(i); | 
 |  | 
 |     if (Arg->isTypeDependent()) | 
 |       return false; | 
 |  | 
 |     ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy, | 
 |                                                AssignmentAction::Passing); | 
 |  | 
 |     if (Res.isInvalid()) | 
 |       return true; | 
 |     TheCall->setArg(i, Res.get()); | 
 |   } | 
 |  | 
 |   Expr *OrigArg = TheCall->getArg(FPArgNo); | 
 |  | 
 |   if (OrigArg->isTypeDependent()) | 
 |     return false; | 
 |  | 
 |   // Usual Unary Conversions will convert half to float, which we want for | 
 |   // machines that use fp16 conversion intrinsics. Else, we wnat to leave the | 
 |   // type how it is, but do normal L->Rvalue conversions. | 
 |   if (Context.getTargetInfo().useFP16ConversionIntrinsics()) { | 
 |     ExprResult Res = UsualUnaryConversions(OrigArg); | 
 |  | 
 |     if (!Res.isUsable()) | 
 |       return true; | 
 |     OrigArg = Res.get(); | 
 |   } else { | 
 |     ExprResult Res = DefaultFunctionArrayLvalueConversion(OrigArg); | 
 |  | 
 |     if (!Res.isUsable()) | 
 |       return true; | 
 |     OrigArg = Res.get(); | 
 |   } | 
 |   TheCall->setArg(FPArgNo, OrigArg); | 
 |  | 
 |   QualType VectorResultTy; | 
 |   QualType ElementTy = OrigArg->getType(); | 
 |   // TODO: When all classification function are implemented with is_fpclass, | 
 |   // vector argument can be supported in all of them. | 
 |   if (ElementTy->isVectorType() && IsFPClass) { | 
 |     VectorResultTy = GetSignedVectorType(ElementTy); | 
 |     ElementTy = ElementTy->castAs<VectorType>()->getElementType(); | 
 |   } | 
 |  | 
 |   // This operation requires a non-_Complex floating-point number. | 
 |   if (!ElementTy->isRealFloatingType()) | 
 |     return Diag(OrigArg->getBeginLoc(), | 
 |                 diag::err_typecheck_call_invalid_unary_fp) | 
 |            << OrigArg->getType() << OrigArg->getSourceRange(); | 
 |  | 
 |   // __builtin_isfpclass has integer parameter that specify test mask. It is | 
 |   // passed in (...), so it should be analyzed completely here. | 
 |   if (IsFPClass) | 
 |     if (BuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) | 
 |       return true; | 
 |  | 
 |   // TODO: enable this code to all classification functions. | 
 |   if (IsFPClass) { | 
 |     QualType ResultTy; | 
 |     if (!VectorResultTy.isNull()) | 
 |       ResultTy = VectorResultTy; | 
 |     else | 
 |       ResultTy = Context.IntTy; | 
 |     TheCall->setType(ResultTy); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinComplex(CallExpr *TheCall) { | 
 |   if (checkArgCount(TheCall, 2)) | 
 |     return true; | 
 |  | 
 |   bool Dependent = false; | 
 |   for (unsigned I = 0; I != 2; ++I) { | 
 |     Expr *Arg = TheCall->getArg(I); | 
 |     QualType T = Arg->getType(); | 
 |     if (T->isDependentType()) { | 
 |       Dependent = true; | 
 |       continue; | 
 |     } | 
 |  | 
 |     // Despite supporting _Complex int, GCC requires a real floating point type | 
 |     // for the operands of __builtin_complex. | 
 |     if (!T->isRealFloatingType()) { | 
 |       return Diag(Arg->getBeginLoc(), diag::err_typecheck_call_requires_real_fp) | 
 |              << Arg->getType() << Arg->getSourceRange(); | 
 |     } | 
 |  | 
 |     ExprResult Converted = DefaultLvalueConversion(Arg); | 
 |     if (Converted.isInvalid()) | 
 |       return true; | 
 |     TheCall->setArg(I, Converted.get()); | 
 |   } | 
 |  | 
 |   if (Dependent) { | 
 |     TheCall->setType(Context.DependentTy); | 
 |     return false; | 
 |   } | 
 |  | 
 |   Expr *Real = TheCall->getArg(0); | 
 |   Expr *Imag = TheCall->getArg(1); | 
 |   if (!Context.hasSameType(Real->getType(), Imag->getType())) { | 
 |     return Diag(Real->getBeginLoc(), | 
 |                 diag::err_typecheck_call_different_arg_types) | 
 |            << Real->getType() << Imag->getType() | 
 |            << Real->getSourceRange() << Imag->getSourceRange(); | 
 |   } | 
 |  | 
 |   TheCall->setType(Context.getComplexType(Real->getType())); | 
 |   return false; | 
 | } | 
 |  | 
 | /// BuiltinShuffleVector - Handle __builtin_shufflevector. | 
 | // This is declared to take (...), so we have to check everything. | 
 | ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { | 
 |   unsigned NumArgs = TheCall->getNumArgs(); | 
 |   if (NumArgs < 2) | 
 |     return ExprError(Diag(TheCall->getEndLoc(), | 
 |                           diag::err_typecheck_call_too_few_args_at_least) | 
 |                      << 0 /*function call*/ << 2 << NumArgs | 
 |                      << /*is non object*/ 0 << TheCall->getSourceRange()); | 
 |  | 
 |   // Determine which of the following types of shufflevector we're checking: | 
 |   // 1) unary, vector mask: (lhs, mask) | 
 |   // 2) binary, scalar mask: (lhs, rhs, index, ..., index) | 
 |   QualType ResType = TheCall->getArg(0)->getType(); | 
 |   unsigned NumElements = 0; | 
 |  | 
 |   if (!TheCall->getArg(0)->isTypeDependent() && | 
 |       !TheCall->getArg(1)->isTypeDependent()) { | 
 |     QualType LHSType = TheCall->getArg(0)->getType(); | 
 |     QualType RHSType = TheCall->getArg(1)->getType(); | 
 |  | 
 |     if (!LHSType->isVectorType() || !RHSType->isVectorType()) | 
 |       return ExprError( | 
 |           Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector) | 
 |           << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ false | 
 |           << SourceRange(TheCall->getArg(0)->getBeginLoc(), | 
 |                          TheCall->getArg(1)->getEndLoc())); | 
 |  | 
 |     NumElements = LHSType->castAs<VectorType>()->getNumElements(); | 
 |     unsigned NumResElements = NumArgs - 2; | 
 |  | 
 |     // Check to see if we have a call with 2 vector arguments, the unary shuffle | 
 |     // with mask.  If so, verify that RHS is an integer vector type with the | 
 |     // same number of elts as lhs. | 
 |     if (NumArgs == 2) { | 
 |       if (!RHSType->hasIntegerRepresentation() || | 
 |           RHSType->castAs<VectorType>()->getNumElements() != NumElements) | 
 |         return ExprError(Diag(TheCall->getBeginLoc(), | 
 |                               diag::err_vec_builtin_incompatible_vector) | 
 |                          << TheCall->getDirectCallee() | 
 |                          << /*isMoreThanTwoArgs*/ false | 
 |                          << SourceRange(TheCall->getArg(1)->getBeginLoc(), | 
 |                                         TheCall->getArg(1)->getEndLoc())); | 
 |     } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { | 
 |       return ExprError(Diag(TheCall->getBeginLoc(), | 
 |                             diag::err_vec_builtin_incompatible_vector) | 
 |                        << TheCall->getDirectCallee() | 
 |                        << /*isMoreThanTwoArgs*/ false | 
 |                        << SourceRange(TheCall->getArg(0)->getBeginLoc(), | 
 |                                       TheCall->getArg(1)->getEndLoc())); | 
 |     } else if (NumElements != NumResElements) { | 
 |       QualType EltType = LHSType->castAs<VectorType>()->getElementType(); | 
 |       ResType = ResType->isExtVectorType() | 
 |                     ? Context.getExtVectorType(EltType, NumResElements) | 
 |                     : Context.getVectorType(EltType, NumResElements, | 
 |                                             VectorKind::Generic); | 
 |     } | 
 |   } | 
 |  | 
 |   for (unsigned I = 2; I != NumArgs; ++I) { | 
 |     Expr *Arg = TheCall->getArg(I); | 
 |     if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |       continue; | 
 |  | 
 |     std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context); | 
 |     if (!Result) | 
 |       return ExprError(Diag(TheCall->getBeginLoc(), | 
 |                             diag::err_shufflevector_nonconstant_argument) | 
 |                        << Arg->getSourceRange()); | 
 |  | 
 |     // Allow -1 which will be translated to undef in the IR. | 
 |     if (Result->isSigned() && Result->isAllOnes()) | 
 |       ; | 
 |     else if (Result->getActiveBits() > 64 || | 
 |              Result->getZExtValue() >= NumElements * 2) | 
 |       return ExprError(Diag(TheCall->getBeginLoc(), | 
 |                             diag::err_shufflevector_argument_too_large) | 
 |                        << Arg->getSourceRange()); | 
 |  | 
 |     TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result))); | 
 |   } | 
 |  | 
 |   auto *Result = new (Context) ShuffleVectorExpr( | 
 |       Context, ArrayRef(TheCall->getArgs(), NumArgs), ResType, | 
 |       TheCall->getCallee()->getBeginLoc(), TheCall->getRParenLoc()); | 
 |  | 
 |   // All moved to Result. | 
 |   TheCall->shrinkNumArgs(0); | 
 |   return Result; | 
 | } | 
 |  | 
 | ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, | 
 |                                    SourceLocation BuiltinLoc, | 
 |                                    SourceLocation RParenLoc) { | 
 |   ExprValueKind VK = VK_PRValue; | 
 |   ExprObjectKind OK = OK_Ordinary; | 
 |   QualType DstTy = TInfo->getType(); | 
 |   QualType SrcTy = E->getType(); | 
 |  | 
 |   if (!SrcTy->isVectorType() && !SrcTy->isDependentType()) | 
 |     return ExprError(Diag(BuiltinLoc, | 
 |                           diag::err_convertvector_non_vector) | 
 |                      << E->getSourceRange()); | 
 |   if (!DstTy->isVectorType() && !DstTy->isDependentType()) | 
 |     return ExprError(Diag(BuiltinLoc, diag::err_builtin_non_vector_type) | 
 |                      << "second" | 
 |                      << "__builtin_convertvector"); | 
 |  | 
 |   if (!SrcTy->isDependentType() && !DstTy->isDependentType()) { | 
 |     unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements(); | 
 |     unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements(); | 
 |     if (SrcElts != DstElts) | 
 |       return ExprError(Diag(BuiltinLoc, | 
 |                             diag::err_convertvector_incompatible_vector) | 
 |                        << E->getSourceRange()); | 
 |   } | 
 |  | 
 |   return ConvertVectorExpr::Create(Context, E, TInfo, DstTy, VK, OK, BuiltinLoc, | 
 |                                    RParenLoc, CurFPFeatureOverrides()); | 
 | } | 
 |  | 
 | bool Sema::BuiltinPrefetch(CallExpr *TheCall) { | 
 |   unsigned NumArgs = TheCall->getNumArgs(); | 
 |  | 
 |   if (NumArgs > 3) | 
 |     return Diag(TheCall->getEndLoc(), | 
 |                 diag::err_typecheck_call_too_many_args_at_most) | 
 |            << 0 /*function call*/ << 3 << NumArgs << /*is non object*/ 0 | 
 |            << TheCall->getSourceRange(); | 
 |  | 
 |   // Argument 0 is checked for us and the remaining arguments must be | 
 |   // constant integers. | 
 |   for (unsigned i = 1; i != NumArgs; ++i) | 
 |     if (BuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) | 
 |       return true; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) { | 
 |   if (!Context.getTargetInfo().checkArithmeticFenceSupported()) | 
 |     return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) | 
 |            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); | 
 |   if (checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |   Expr *Arg = TheCall->getArg(0); | 
 |   if (Arg->isInstantiationDependent()) | 
 |     return false; | 
 |  | 
 |   QualType ArgTy = Arg->getType(); | 
 |   if (!ArgTy->hasFloatingRepresentation()) | 
 |     return Diag(TheCall->getEndLoc(), diag::err_typecheck_expect_flt_or_vector) | 
 |            << ArgTy; | 
 |   if (Arg->isLValue()) { | 
 |     ExprResult FirstArg = DefaultLvalueConversion(Arg); | 
 |     TheCall->setArg(0, FirstArg.get()); | 
 |   } | 
 |   TheCall->setType(TheCall->getArg(0)->getType()); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinAssume(CallExpr *TheCall) { | 
 |   Expr *Arg = TheCall->getArg(0); | 
 |   if (Arg->isInstantiationDependent()) return false; | 
 |  | 
 |   if (Arg->HasSideEffects(Context)) | 
 |     Diag(Arg->getBeginLoc(), diag::warn_assume_side_effects) | 
 |         << Arg->getSourceRange() | 
 |         << cast<FunctionDecl>(TheCall->getCalleeDecl())->getIdentifier(); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinAllocaWithAlign(CallExpr *TheCall) { | 
 |   // The alignment must be a constant integer. | 
 |   Expr *Arg = TheCall->getArg(1); | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { | 
 |     if (const auto *UE = | 
 |             dyn_cast<UnaryExprOrTypeTraitExpr>(Arg->IgnoreParenImpCasts())) | 
 |       if (UE->getKind() == UETT_AlignOf || | 
 |           UE->getKind() == UETT_PreferredAlignOf) | 
 |         Diag(TheCall->getBeginLoc(), diag::warn_alloca_align_alignof) | 
 |             << Arg->getSourceRange(); | 
 |  | 
 |     llvm::APSInt Result = Arg->EvaluateKnownConstInt(Context); | 
 |  | 
 |     if (!Result.isPowerOf2()) | 
 |       return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two) | 
 |              << Arg->getSourceRange(); | 
 |  | 
 |     if (Result < Context.getCharWidth()) | 
 |       return Diag(TheCall->getBeginLoc(), diag::err_alignment_too_small) | 
 |              << (unsigned)Context.getCharWidth() << Arg->getSourceRange(); | 
 |  | 
 |     if (Result > std::numeric_limits<int32_t>::max()) | 
 |       return Diag(TheCall->getBeginLoc(), diag::err_alignment_too_big) | 
 |              << std::numeric_limits<int32_t>::max() << Arg->getSourceRange(); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) { | 
 |   if (checkArgCountRange(TheCall, 2, 3)) | 
 |     return true; | 
 |  | 
 |   unsigned NumArgs = TheCall->getNumArgs(); | 
 |   Expr *FirstArg = TheCall->getArg(0); | 
 |  | 
 |   { | 
 |     ExprResult FirstArgResult = | 
 |         DefaultFunctionArrayLvalueConversion(FirstArg); | 
 |     if (!FirstArgResult.get()->getType()->isPointerType()) { | 
 |       Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg) | 
 |           << TheCall->getSourceRange(); | 
 |       return true; | 
 |     } | 
 |     TheCall->setArg(0, FirstArgResult.get()); | 
 |   } | 
 |  | 
 |   // The alignment must be a constant integer. | 
 |   Expr *SecondArg = TheCall->getArg(1); | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   if (!SecondArg->isValueDependent()) { | 
 |     llvm::APSInt Result; | 
 |     if (BuiltinConstantArg(TheCall, 1, Result)) | 
 |       return true; | 
 |  | 
 |     if (!Result.isPowerOf2()) | 
 |       return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two) | 
 |              << SecondArg->getSourceRange(); | 
 |  | 
 |     if (Result > Sema::MaximumAlignment) | 
 |       Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great) | 
 |           << SecondArg->getSourceRange() << Sema::MaximumAlignment; | 
 |  | 
 |     TheCall->setArg(1, | 
 |                     ConstantExpr::Create(Context, SecondArg, APValue(Result))); | 
 |   } | 
 |  | 
 |   if (NumArgs > 2) { | 
 |     Expr *ThirdArg = TheCall->getArg(2); | 
 |     if (convertArgumentToType(*this, ThirdArg, Context.getSizeType())) | 
 |       return true; | 
 |     TheCall->setArg(2, ThirdArg); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinOSLogFormat(CallExpr *TheCall) { | 
 |   unsigned BuiltinID = | 
 |       cast<FunctionDecl>(TheCall->getCalleeDecl())->getBuiltinID(); | 
 |   bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; | 
 |  | 
 |   unsigned NumArgs = TheCall->getNumArgs(); | 
 |   unsigned NumRequiredArgs = IsSizeCall ? 1 : 2; | 
 |   if (NumArgs < NumRequiredArgs) { | 
 |     return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args) | 
 |            << 0 /* function call */ << NumRequiredArgs << NumArgs | 
 |            << /*is non object*/ 0 << TheCall->getSourceRange(); | 
 |   } | 
 |   if (NumArgs >= NumRequiredArgs + 0x100) { | 
 |     return Diag(TheCall->getEndLoc(), | 
 |                 diag::err_typecheck_call_too_many_args_at_most) | 
 |            << 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs | 
 |            << /*is non object*/ 0 << TheCall->getSourceRange(); | 
 |   } | 
 |   unsigned i = 0; | 
 |  | 
 |   // For formatting call, check buffer arg. | 
 |   if (!IsSizeCall) { | 
 |     ExprResult Arg(TheCall->getArg(i)); | 
 |     InitializedEntity Entity = InitializedEntity::InitializeParameter( | 
 |         Context, Context.VoidPtrTy, false); | 
 |     Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); | 
 |     if (Arg.isInvalid()) | 
 |       return true; | 
 |     TheCall->setArg(i, Arg.get()); | 
 |     i++; | 
 |   } | 
 |  | 
 |   // Check string literal arg. | 
 |   unsigned FormatIdx = i; | 
 |   { | 
 |     ExprResult Arg = CheckOSLogFormatStringArg(TheCall->getArg(i)); | 
 |     if (Arg.isInvalid()) | 
 |       return true; | 
 |     TheCall->setArg(i, Arg.get()); | 
 |     i++; | 
 |   } | 
 |  | 
 |   // Make sure variadic args are scalar. | 
 |   unsigned FirstDataArg = i; | 
 |   while (i < NumArgs) { | 
 |     ExprResult Arg = DefaultVariadicArgumentPromotion( | 
 |         TheCall->getArg(i), VariadicCallType::Function, nullptr); | 
 |     if (Arg.isInvalid()) | 
 |       return true; | 
 |     CharUnits ArgSize = Context.getTypeSizeInChars(Arg.get()->getType()); | 
 |     if (ArgSize.getQuantity() >= 0x100) { | 
 |       return Diag(Arg.get()->getEndLoc(), diag::err_os_log_argument_too_big) | 
 |              << i << (int)ArgSize.getQuantity() << 0xff | 
 |              << TheCall->getSourceRange(); | 
 |     } | 
 |     TheCall->setArg(i, Arg.get()); | 
 |     i++; | 
 |   } | 
 |  | 
 |   // Check formatting specifiers. NOTE: We're only doing this for the non-size | 
 |   // call to avoid duplicate diagnostics. | 
 |   if (!IsSizeCall) { | 
 |     llvm::SmallBitVector CheckedVarArgs(NumArgs, false); | 
 |     ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs()); | 
 |     bool Success = CheckFormatArguments( | 
 |         Args, FAPK_Variadic, nullptr, FormatIdx, FirstDataArg, | 
 |         FormatStringType::OSLog, VariadicCallType::Function, | 
 |         TheCall->getBeginLoc(), SourceRange(), CheckedVarArgs); | 
 |     if (!Success) | 
 |       return true; | 
 |   } | 
 |  | 
 |   if (IsSizeCall) { | 
 |     TheCall->setType(Context.getSizeType()); | 
 |   } else { | 
 |     TheCall->setType(Context.VoidPtrTy); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinConstantArg(CallExpr *TheCall, unsigned ArgNum, | 
 |                               llvm::APSInt &Result) { | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |  | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   std::optional<llvm::APSInt> R = Arg->getIntegerConstantExpr(Context); | 
 |   if (!R) { | 
 |     auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); | 
 |     auto *FDecl = cast<FunctionDecl>(DRE->getDecl()); | 
 |     return Diag(TheCall->getBeginLoc(), diag::err_constant_integer_arg_type) | 
 |            << FDecl->getDeclName() << Arg->getSourceRange(); | 
 |   } | 
 |   Result = *R; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinConstantArgRange(CallExpr *TheCall, unsigned ArgNum, int Low, | 
 |                                    int High, bool RangeIsError) { | 
 |   if (isConstantEvaluatedContext()) | 
 |     return false; | 
 |   llvm::APSInt Result; | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   // Check constant-ness first. | 
 |   if (BuiltinConstantArg(TheCall, ArgNum, Result)) | 
 |     return true; | 
 |  | 
 |   if (Result.getSExtValue() < Low || Result.getSExtValue() > High) { | 
 |     if (RangeIsError) | 
 |       return Diag(TheCall->getBeginLoc(), diag::err_argument_invalid_range) | 
 |              << toString(Result, 10) << Low << High << Arg->getSourceRange(); | 
 |     else | 
 |       // Defer the warning until we know if the code will be emitted so that | 
 |       // dead code can ignore this. | 
 |       DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, | 
 |                           PDiag(diag::warn_argument_invalid_range) | 
 |                               << toString(Result, 10) << Low << High | 
 |                               << Arg->getSourceRange()); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinConstantArgMultiple(CallExpr *TheCall, unsigned ArgNum, | 
 |                                       unsigned Num) { | 
 |   llvm::APSInt Result; | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   // Check constant-ness first. | 
 |   if (BuiltinConstantArg(TheCall, ArgNum, Result)) | 
 |     return true; | 
 |  | 
 |   if (Result.getSExtValue() % Num != 0) | 
 |     return Diag(TheCall->getBeginLoc(), diag::err_argument_not_multiple) | 
 |            << Num << Arg->getSourceRange(); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinConstantArgPower2(CallExpr *TheCall, unsigned ArgNum) { | 
 |   llvm::APSInt Result; | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   // Check constant-ness first. | 
 |   if (BuiltinConstantArg(TheCall, ArgNum, Result)) | 
 |     return true; | 
 |  | 
 |   if (Result.isPowerOf2()) | 
 |     return false; | 
 |  | 
 |   return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2) | 
 |          << Arg->getSourceRange(); | 
 | } | 
 |  | 
 | static bool IsShiftedByte(llvm::APSInt Value) { | 
 |   if (Value.isNegative()) | 
 |     return false; | 
 |  | 
 |   // Check if it's a shifted byte, by shifting it down | 
 |   while (true) { | 
 |     // If the value fits in the bottom byte, the check passes. | 
 |     if (Value < 0x100) | 
 |       return true; | 
 |  | 
 |     // Otherwise, if the value has _any_ bits in the bottom byte, the check | 
 |     // fails. | 
 |     if ((Value & 0xFF) != 0) | 
 |       return false; | 
 |  | 
 |     // If the bottom 8 bits are all 0, but something above that is nonzero, | 
 |     // then shifting the value right by 8 bits won't affect whether it's a | 
 |     // shifted byte or not. So do that, and go round again. | 
 |     Value >>= 8; | 
 |   } | 
 | } | 
 |  | 
 | bool Sema::BuiltinConstantArgShiftedByte(CallExpr *TheCall, unsigned ArgNum, | 
 |                                          unsigned ArgBits) { | 
 |   llvm::APSInt Result; | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   // Check constant-ness first. | 
 |   if (BuiltinConstantArg(TheCall, ArgNum, Result)) | 
 |     return true; | 
 |  | 
 |   // Truncate to the given size. | 
 |   Result = Result.getLoBits(ArgBits); | 
 |   Result.setIsUnsigned(true); | 
 |  | 
 |   if (IsShiftedByte(Result)) | 
 |     return false; | 
 |  | 
 |   return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte) | 
 |          << Arg->getSourceRange(); | 
 | } | 
 |  | 
 | bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, | 
 |                                                unsigned ArgNum, | 
 |                                                unsigned ArgBits) { | 
 |   llvm::APSInt Result; | 
 |  | 
 |   // We can't check the value of a dependent argument. | 
 |   Expr *Arg = TheCall->getArg(ArgNum); | 
 |   if (Arg->isTypeDependent() || Arg->isValueDependent()) | 
 |     return false; | 
 |  | 
 |   // Check constant-ness first. | 
 |   if (BuiltinConstantArg(TheCall, ArgNum, Result)) | 
 |     return true; | 
 |  | 
 |   // Truncate to the given size. | 
 |   Result = Result.getLoBits(ArgBits); | 
 |   Result.setIsUnsigned(true); | 
 |  | 
 |   // Check to see if it's in either of the required forms. | 
 |   if (IsShiftedByte(Result) || | 
 |       (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF)) | 
 |     return false; | 
 |  | 
 |   return Diag(TheCall->getBeginLoc(), | 
 |               diag::err_argument_not_shifted_byte_or_xxff) | 
 |          << Arg->getSourceRange(); | 
 | } | 
 |  | 
 | bool Sema::BuiltinLongjmp(CallExpr *TheCall) { | 
 |   if (!Context.getTargetInfo().hasSjLjLowering()) | 
 |     return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_unsupported) | 
 |            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); | 
 |  | 
 |   Expr *Arg = TheCall->getArg(1); | 
 |   llvm::APSInt Result; | 
 |  | 
 |   // TODO: This is less than ideal. Overload this to take a value. | 
 |   if (BuiltinConstantArg(TheCall, 1, Result)) | 
 |     return true; | 
 |  | 
 |   if (Result != 1) | 
 |     return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_invalid_val) | 
 |            << SourceRange(Arg->getBeginLoc(), Arg->getEndLoc()); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinSetjmp(CallExpr *TheCall) { | 
 |   if (!Context.getTargetInfo().hasSjLjLowering()) | 
 |     return Diag(TheCall->getBeginLoc(), diag::err_builtin_setjmp_unsupported) | 
 |            << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinCountedByRef(CallExpr *TheCall) { | 
 |   if (checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   ExprResult ArgRes = UsualUnaryConversions(TheCall->getArg(0)); | 
 |   if (ArgRes.isInvalid()) | 
 |     return true; | 
 |  | 
 |   // For simplicity, we support only limited expressions for the argument. | 
 |   // Specifically a pointer to a flexible array member:'ptr->array'. This | 
 |   // allows us to reject arguments with complex casting, which really shouldn't | 
 |   // be a huge problem. | 
 |   const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts(); | 
 |   if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType()) | 
 |     return Diag(Arg->getBeginLoc(), | 
 |                 diag::err_builtin_counted_by_ref_must_be_flex_array_member) | 
 |            << Arg->getSourceRange(); | 
 |  | 
 |   if (Arg->HasSideEffects(Context)) | 
 |     return Diag(Arg->getBeginLoc(), | 
 |                 diag::err_builtin_counted_by_ref_has_side_effects) | 
 |            << Arg->getSourceRange(); | 
 |  | 
 |   if (const auto *ME = dyn_cast<MemberExpr>(Arg)) { | 
 |     if (!ME->isFlexibleArrayMemberLike( | 
 |             Context, getLangOpts().getStrictFlexArraysLevel())) | 
 |       return Diag(Arg->getBeginLoc(), | 
 |                   diag::err_builtin_counted_by_ref_must_be_flex_array_member) | 
 |              << Arg->getSourceRange(); | 
 |  | 
 |     if (auto *CATy = | 
 |             ME->getMemberDecl()->getType()->getAs<CountAttributedType>(); | 
 |         CATy && CATy->getKind() == CountAttributedType::CountedBy) { | 
 |       const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl()); | 
 |       if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) { | 
 |         TheCall->setType(Context.getPointerType(CountFD->getType())); | 
 |         return false; | 
 |       } | 
 |     } | 
 |   } else { | 
 |     return Diag(Arg->getBeginLoc(), | 
 |                 diag::err_builtin_counted_by_ref_must_be_flex_array_member) | 
 |            << Arg->getSourceRange(); | 
 |   } | 
 |  | 
 |   TheCall->setType(Context.getPointerType(Context.VoidTy)); | 
 |   return false; | 
 | } | 
 |  | 
 | /// The result of __builtin_counted_by_ref cannot be assigned to a variable. | 
 | /// It allows leaking and modification of bounds safety information. | 
 | bool Sema::CheckInvalidBuiltinCountedByRef(const Expr *E, | 
 |                                            BuiltinCountedByRefKind K) { | 
 |   const CallExpr *CE = | 
 |       E ? dyn_cast<CallExpr>(E->IgnoreParenImpCasts()) : nullptr; | 
 |   if (!CE || CE->getBuiltinCallee() != Builtin::BI__builtin_counted_by_ref) | 
 |     return false; | 
 |  | 
 |   switch (K) { | 
 |   case BuiltinCountedByRefKind::Assignment: | 
 |   case BuiltinCountedByRefKind::Initializer: | 
 |     Diag(E->getExprLoc(), | 
 |          diag::err_builtin_counted_by_ref_cannot_leak_reference) | 
 |         << 0 << E->getSourceRange(); | 
 |     break; | 
 |   case BuiltinCountedByRefKind::FunctionArg: | 
 |     Diag(E->getExprLoc(), | 
 |          diag::err_builtin_counted_by_ref_cannot_leak_reference) | 
 |         << 1 << E->getSourceRange(); | 
 |     break; | 
 |   case BuiltinCountedByRefKind::ReturnArg: | 
 |     Diag(E->getExprLoc(), | 
 |          diag::err_builtin_counted_by_ref_cannot_leak_reference) | 
 |         << 2 << E->getSourceRange(); | 
 |     break; | 
 |   case BuiltinCountedByRefKind::ArraySubscript: | 
 |     Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_use) | 
 |         << 0 << E->getSourceRange(); | 
 |     break; | 
 |   case BuiltinCountedByRefKind::BinaryExpr: | 
 |     Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_use) | 
 |         << 1 << E->getSourceRange(); | 
 |     break; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | class UncoveredArgHandler { | 
 |   enum { Unknown = -1, AllCovered = -2 }; | 
 |  | 
 |   signed FirstUncoveredArg = Unknown; | 
 |   SmallVector<const Expr *, 4> DiagnosticExprs; | 
 |  | 
 | public: | 
 |   UncoveredArgHandler() = default; | 
 |  | 
 |   bool hasUncoveredArg() const { | 
 |     return (FirstUncoveredArg >= 0); | 
 |   } | 
 |  | 
 |   unsigned getUncoveredArg() const { | 
 |     assert(hasUncoveredArg() && "no uncovered argument"); | 
 |     return FirstUncoveredArg; | 
 |   } | 
 |  | 
 |   void setAllCovered() { | 
 |     // A string has been found with all arguments covered, so clear out | 
 |     // the diagnostics. | 
 |     DiagnosticExprs.clear(); | 
 |     FirstUncoveredArg = AllCovered; | 
 |   } | 
 |  | 
 |   void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) { | 
 |     assert(NewFirstUncoveredArg >= 0 && "Outside range"); | 
 |  | 
 |     // Don't update if a previous string covers all arguments. | 
 |     if (FirstUncoveredArg == AllCovered) | 
 |       return; | 
 |  | 
 |     // UncoveredArgHandler tracks the highest uncovered argument index | 
 |     // and with it all the strings that match this index. | 
 |     if (NewFirstUncoveredArg == FirstUncoveredArg) | 
 |       DiagnosticExprs.push_back(StrExpr); | 
 |     else if (NewFirstUncoveredArg > FirstUncoveredArg) { | 
 |       DiagnosticExprs.clear(); | 
 |       DiagnosticExprs.push_back(StrExpr); | 
 |       FirstUncoveredArg = NewFirstUncoveredArg; | 
 |     } | 
 |   } | 
 |  | 
 |   void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr); | 
 | }; | 
 |  | 
 | enum StringLiteralCheckType { | 
 |   SLCT_NotALiteral, | 
 |   SLCT_UncheckedLiteral, | 
 |   SLCT_CheckedLiteral | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, | 
 |                                      BinaryOperatorKind BinOpKind, | 
 |                                      bool AddendIsRight) { | 
 |   unsigned BitWidth = Offset.getBitWidth(); | 
 |   unsigned AddendBitWidth = Addend.getBitWidth(); | 
 |   // There might be negative interim results. | 
 |   if (Addend.isUnsigned()) { | 
 |     Addend = Addend.zext(++AddendBitWidth); | 
 |     Addend.setIsSigned(true); | 
 |   } | 
 |   // Adjust the bit width of the APSInts. | 
 |   if (AddendBitWidth > BitWidth) { | 
 |     Offset = Offset.sext(AddendBitWidth); | 
 |     BitWidth = AddendBitWidth; | 
 |   } else if (BitWidth > AddendBitWidth) { | 
 |     Addend = Addend.sext(BitWidth); | 
 |   } | 
 |  | 
 |   bool Ov = false; | 
 |   llvm::APSInt ResOffset = Offset; | 
 |   if (BinOpKind == BO_Add) | 
 |     ResOffset = Offset.sadd_ov(Addend, Ov); | 
 |   else { | 
 |     assert(AddendIsRight && BinOpKind == BO_Sub && | 
 |            "operator must be add or sub with addend on the right"); | 
 |     ResOffset = Offset.ssub_ov(Addend, Ov); | 
 |   } | 
 |  | 
 |   // We add an offset to a pointer here so we should support an offset as big as | 
 |   // possible. | 
 |   if (Ov) { | 
 |     assert(BitWidth <= std::numeric_limits<unsigned>::max() / 2 && | 
 |            "index (intermediate) result too big"); | 
 |     Offset = Offset.sext(2 * BitWidth); | 
 |     sumOffsets(Offset, Addend, BinOpKind, AddendIsRight); | 
 |     return; | 
 |   } | 
 |  | 
 |   Offset = ResOffset; | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // This is a wrapper class around StringLiteral to support offsetted string | 
 | // literals as format strings. It takes the offset into account when returning | 
 | // the string and its length or the source locations to display notes correctly. | 
 | class FormatStringLiteral { | 
 |   const StringLiteral *FExpr; | 
 |   int64_t Offset; | 
 |  | 
 | public: | 
 |   FormatStringLiteral(const StringLiteral *fexpr, int64_t Offset = 0) | 
 |       : FExpr(fexpr), Offset(Offset) {} | 
 |  | 
 |   const StringLiteral *getFormatString() const { return FExpr; } | 
 |  | 
 |   StringRef getString() const { return FExpr->getString().drop_front(Offset); } | 
 |  | 
 |   unsigned getByteLength() const { | 
 |     return FExpr->getByteLength() - getCharByteWidth() * Offset; | 
 |   } | 
 |  | 
 |   unsigned getLength() const { return FExpr->getLength() - Offset; } | 
 |   unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); } | 
 |  | 
 |   StringLiteralKind getKind() const { return FExpr->getKind(); } | 
 |  | 
 |   QualType getType() const { return FExpr->getType(); } | 
 |  | 
 |   bool isAscii() const { return FExpr->isOrdinary(); } | 
 |   bool isWide() const { return FExpr->isWide(); } | 
 |   bool isUTF8() const { return FExpr->isUTF8(); } | 
 |   bool isUTF16() const { return FExpr->isUTF16(); } | 
 |   bool isUTF32() const { return FExpr->isUTF32(); } | 
 |   bool isPascal() const { return FExpr->isPascal(); } | 
 |  | 
 |   SourceLocation getLocationOfByte( | 
 |       unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, | 
 |       const TargetInfo &Target, unsigned *StartToken = nullptr, | 
 |       unsigned *StartTokenByteOffset = nullptr) const { | 
 |     return FExpr->getLocationOfByte(ByteNo + Offset, SM, Features, Target, | 
 |                                     StartToken, StartTokenByteOffset); | 
 |   } | 
 |  | 
 |   SourceLocation getBeginLoc() const LLVM_READONLY { | 
 |     return FExpr->getBeginLoc().getLocWithOffset(Offset); | 
 |   } | 
 |  | 
 |   SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getEndLoc(); } | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | static void CheckFormatString( | 
 |     Sema &S, const FormatStringLiteral *FExpr, | 
 |     const StringLiteral *ReferenceFormatString, const Expr *OrigFormatExpr, | 
 |     ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK, | 
 |     unsigned format_idx, unsigned firstDataArg, FormatStringType Type, | 
 |     bool inFunctionCall, VariadicCallType CallType, | 
 |     llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, | 
 |     bool IgnoreStringsWithoutSpecifiers); | 
 |  | 
 | static const Expr *maybeConstEvalStringLiteral(ASTContext &Context, | 
 |                                                const Expr *E); | 
 |  | 
 | // Determine if an expression is a string literal or constant string. | 
 | // If this function returns false on the arguments to a function expecting a | 
 | // format string, we will usually need to emit a warning. | 
 | // True string literals are then checked by CheckFormatString. | 
 | static StringLiteralCheckType checkFormatStringExpr( | 
 |     Sema &S, const StringLiteral *ReferenceFormatString, const Expr *E, | 
 |     ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK, | 
 |     unsigned format_idx, unsigned firstDataArg, FormatStringType Type, | 
 |     VariadicCallType CallType, bool InFunctionCall, | 
 |     llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, | 
 |     llvm::APSInt Offset, bool IgnoreStringsWithoutSpecifiers = false) { | 
 |   if (S.isConstantEvaluatedContext()) | 
 |     return SLCT_NotALiteral; | 
 | tryAgain: | 
 |   assert(Offset.isSigned() && "invalid offset"); | 
 |  | 
 |   if (E->isTypeDependent() || E->isValueDependent()) | 
 |     return SLCT_NotALiteral; | 
 |  | 
 |   E = E->IgnoreParenCasts(); | 
 |  | 
 |   if (E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) | 
 |     // Technically -Wformat-nonliteral does not warn about this case. | 
 |     // The behavior of printf and friends in this case is implementation | 
 |     // dependent.  Ideally if the format string cannot be null then | 
 |     // it should have a 'nonnull' attribute in the function prototype. | 
 |     return SLCT_UncheckedLiteral; | 
 |  | 
 |   switch (E->getStmtClass()) { | 
 |   case Stmt::InitListExprClass: | 
 |     // Handle expressions like {"foobar"}. | 
 |     if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) { | 
 |       return checkFormatStringExpr( | 
 |           S, ReferenceFormatString, SLE, Args, APK, format_idx, firstDataArg, | 
 |           Type, CallType, /*InFunctionCall*/ false, CheckedVarArgs, | 
 |           UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); | 
 |     } | 
 |     return SLCT_NotALiteral; | 
 |   case Stmt::BinaryConditionalOperatorClass: | 
 |   case Stmt::ConditionalOperatorClass: { | 
 |     // The expression is a literal if both sub-expressions were, and it was | 
 |     // completely checked only if both sub-expressions were checked. | 
 |     const AbstractConditionalOperator *C = | 
 |         cast<AbstractConditionalOperator>(E); | 
 |  | 
 |     // Determine whether it is necessary to check both sub-expressions, for | 
 |     // example, because the condition expression is a constant that can be | 
 |     // evaluated at compile time. | 
 |     bool CheckLeft = true, CheckRight = true; | 
 |  | 
 |     bool Cond; | 
 |     if (C->getCond()->EvaluateAsBooleanCondition( | 
 |             Cond, S.getASTContext(), S.isConstantEvaluatedContext())) { | 
 |       if (Cond) | 
 |         CheckRight = false; | 
 |       else | 
 |         CheckLeft = false; | 
 |     } | 
 |  | 
 |     // We need to maintain the offsets for the right and the left hand side | 
 |     // separately to check if every possible indexed expression is a valid | 
 |     // string literal. They might have different offsets for different string | 
 |     // literals in the end. | 
 |     StringLiteralCheckType Left; | 
 |     if (!CheckLeft) | 
 |       Left = SLCT_UncheckedLiteral; | 
 |     else { | 
 |       Left = checkFormatStringExpr( | 
 |           S, ReferenceFormatString, C->getTrueExpr(), Args, APK, format_idx, | 
 |           firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, | 
 |           UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); | 
 |       if (Left == SLCT_NotALiteral || !CheckRight) { | 
 |         return Left; | 
 |       } | 
 |     } | 
 |  | 
 |     StringLiteralCheckType Right = checkFormatStringExpr( | 
 |         S, ReferenceFormatString, C->getFalseExpr(), Args, APK, format_idx, | 
 |         firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, | 
 |         UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); | 
 |  | 
 |     return (CheckLeft && Left < Right) ? Left : Right; | 
 |   } | 
 |  | 
 |   case Stmt::ImplicitCastExprClass: | 
 |     E = cast<ImplicitCastExpr>(E)->getSubExpr(); | 
 |     goto tryAgain; | 
 |  | 
 |   case Stmt::OpaqueValueExprClass: | 
 |     if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) { | 
 |       E = src; | 
 |       goto tryAgain; | 
 |     } | 
 |     return SLCT_NotALiteral; | 
 |  | 
 |   case Stmt::PredefinedExprClass: | 
 |     // While __func__, etc., are technically not string literals, they | 
 |     // cannot contain format specifiers and thus are not a security | 
 |     // liability. | 
 |     return SLCT_UncheckedLiteral; | 
 |  | 
 |   case Stmt::DeclRefExprClass: { | 
 |     const DeclRefExpr *DR = cast<DeclRefExpr>(E); | 
 |  | 
 |     // As an exception, do not flag errors for variables binding to | 
 |     // const string literals. | 
 |     if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { | 
 |       bool isConstant = false; | 
 |       QualType T = DR->getType(); | 
 |  | 
 |       if (const ArrayType *AT = S.Context.getAsArrayType(T)) { | 
 |         isConstant = AT->getElementType().isConstant(S.Context); | 
 |       } else if (const PointerType *PT = T->getAs<PointerType>()) { | 
 |         isConstant = T.isConstant(S.Context) && | 
 |                      PT->getPointeeType().isConstant(S.Context); | 
 |       } else if (T->isObjCObjectPointerType()) { | 
 |         // In ObjC, there is usually no "const ObjectPointer" type, | 
 |         // so don't check if the pointee type is constant. | 
 |         isConstant = T.isConstant(S.Context); | 
 |       } | 
 |  | 
 |       if (isConstant) { | 
 |         if (const Expr *Init = VD->getAnyInitializer()) { | 
 |           // Look through initializers like const char c[] = { "foo" } | 
 |           if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) { | 
 |             if (InitList->isStringLiteralInit()) | 
 |               Init = InitList->getInit(0)->IgnoreParenImpCasts(); | 
 |           } | 
 |           return checkFormatStringExpr( | 
 |               S, ReferenceFormatString, Init, Args, APK, format_idx, | 
 |               firstDataArg, Type, CallType, | 
 |               /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, Offset); | 
 |         } | 
 |       } | 
 |  | 
 |       // When the format argument is an argument of this function, and this | 
 |       // function also has the format attribute, there are several interactions | 
 |       // for which there shouldn't be a warning. For instance, when calling | 
 |       // v*printf from a function that has the printf format attribute, we | 
 |       // should not emit a warning about using `fmt`, even though it's not | 
 |       // constant, because the arguments have already been checked for the | 
 |       // caller of `logmessage`: | 
 |       // | 
 |       //  __attribute__((format(printf, 1, 2))) | 
 |       //  void logmessage(char const *fmt, ...) { | 
 |       //    va_list ap; | 
 |       //    va_start(ap, fmt); | 
 |       //    vprintf(fmt, ap);  /* do not emit a warning about "fmt" */ | 
 |       //    ... | 
 |       // } | 
 |       // | 
 |       // Another interaction that we need to support is using a format string | 
 |       // specified by the format_matches attribute: | 
 |       // | 
 |       //  __attribute__((format_matches(printf, 1, "%s %d"))) | 
 |       //  void logmessage(char const *fmt, const char *a, int b) { | 
 |       //    printf(fmt, a, b); /* do not emit a warning about "fmt" */ | 
 |       //    printf(fmt, 123.4); /* emit warnings that "%s %d" is incompatible */ | 
 |       //    ... | 
 |       // } | 
 |       // | 
 |       // Yet another interaction that we need to support is calling a variadic | 
 |       // format function from a format function that has fixed arguments. For | 
 |       // instance: | 
 |       // | 
 |       //  __attribute__((format(printf, 1, 2))) | 
 |       //  void logstring(char const *fmt, char const *str) { | 
 |       //    printf(fmt, str);  /* do not emit a warning about "fmt" */ | 
 |       //  } | 
 |       // | 
 |       // Same (and perhaps more relatably) for the variadic template case: | 
 |       // | 
 |       //  template<typename... Args> | 
 |       //  __attribute__((format(printf, 1, 2))) | 
 |       //  void log(const char *fmt, Args&&... args) { | 
 |       //    printf(fmt, forward<Args>(args)...); | 
 |       //           /* do not emit a warning about "fmt" */ | 
 |       //  } | 
 |       // | 
 |       // Due to implementation difficulty, we only check the format, not the | 
 |       // format arguments, in all cases. | 
 |       // | 
 |       if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) { | 
 |         if (const auto *D = dyn_cast<Decl>(PV->getDeclContext())) { | 
 |           for (const auto *PVFormatMatches : | 
 |                D->specific_attrs<FormatMatchesAttr>()) { | 
 |             Sema::FormatStringInfo CalleeFSI; | 
 |             if (!Sema::getFormatStringInfo(D, PVFormatMatches->getFormatIdx(), | 
 |                                            0, &CalleeFSI)) | 
 |               continue; | 
 |             if (PV->getFunctionScopeIndex() == CalleeFSI.FormatIdx) { | 
 |               // If using the wrong type of format string, emit a diagnostic | 
 |               // here and stop checking to avoid irrelevant diagnostics. | 
 |               if (Type != S.GetFormatStringType(PVFormatMatches)) { | 
 |                 S.Diag(Args[format_idx]->getBeginLoc(), | 
 |                        diag::warn_format_string_type_incompatible) | 
 |                     << PVFormatMatches->getType()->getName() | 
 |                     << S.GetFormatStringTypeName(Type); | 
 |                 if (!InFunctionCall) { | 
 |                   S.Diag(PVFormatMatches->getFormatString()->getBeginLoc(), | 
 |                          diag::note_format_string_defined); | 
 |                 } | 
 |                 return SLCT_UncheckedLiteral; | 
 |               } | 
 |               return checkFormatStringExpr( | 
 |                   S, ReferenceFormatString, PVFormatMatches->getFormatString(), | 
 |                   Args, APK, format_idx, firstDataArg, Type, CallType, | 
 |                   /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, | 
 |                   Offset, IgnoreStringsWithoutSpecifiers); | 
 |             } | 
 |           } | 
 |  | 
 |           for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) { | 
 |             Sema::FormatStringInfo CallerFSI; | 
 |             if (!Sema::getFormatStringInfo(D, PVFormat->getFormatIdx(), | 
 |                                            PVFormat->getFirstArg(), &CallerFSI)) | 
 |               continue; | 
 |             if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) { | 
 |               // We also check if the formats are compatible. | 
 |               // We can't pass a 'scanf' string to a 'printf' function. | 
 |               if (Type != S.GetFormatStringType(PVFormat)) { | 
 |                 S.Diag(Args[format_idx]->getBeginLoc(), | 
 |                        diag::warn_format_string_type_incompatible) | 
 |                     << PVFormat->getType()->getName() | 
 |                     << S.GetFormatStringTypeName(Type); | 
 |                 if (!InFunctionCall) { | 
 |                   S.Diag(E->getBeginLoc(), diag::note_format_string_defined); | 
 |                 } | 
 |                 return SLCT_UncheckedLiteral; | 
 |               } | 
 |               // Lastly, check that argument passing kinds transition in a | 
 |               // way that makes sense: | 
 |               // from a caller with FAPK_VAList, allow FAPK_VAList | 
 |               // from a caller with FAPK_Fixed, allow FAPK_Fixed | 
 |               // from a caller with FAPK_Fixed, allow FAPK_Variadic | 
 |               // from a caller with FAPK_Variadic, allow FAPK_VAList | 
 |               switch (combineFAPK(CallerFSI.ArgPassingKind, APK)) { | 
 |               case combineFAPK(Sema::FAPK_VAList, Sema::FAPK_VAList): | 
 |               case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Fixed): | 
 |               case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Variadic): | 
 |               case combineFAPK(Sema::FAPK_Variadic, Sema::FAPK_VAList): | 
 |                 return SLCT_UncheckedLiteral; | 
 |               } | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 |  | 
 |   case Stmt::CallExprClass: | 
 |   case Stmt::CXXMemberCallExprClass: { | 
 |     const CallExpr *CE = cast<CallExpr>(E); | 
 |     if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { | 
 |       bool IsFirst = true; | 
 |       StringLiteralCheckType CommonResult; | 
 |       for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { | 
 |         const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); | 
 |         StringLiteralCheckType Result = checkFormatStringExpr( | 
 |             S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg, | 
 |             Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, | 
 |             Offset, IgnoreStringsWithoutSpecifiers); | 
 |         if (IsFirst) { | 
 |           CommonResult = Result; | 
 |           IsFirst = false; | 
 |         } | 
 |       } | 
 |       if (!IsFirst) | 
 |         return CommonResult; | 
 |  | 
 |       if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { | 
 |         unsigned BuiltinID = FD->getBuiltinID(); | 
 |         if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || | 
 |             BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { | 
 |           const Expr *Arg = CE->getArg(0); | 
 |           return checkFormatStringExpr( | 
 |               S, ReferenceFormatString, Arg, Args, APK, format_idx, | 
 |               firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, | 
 |               UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); | 
 |         } | 
 |       } | 
 |     } | 
 |     if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) | 
 |       return checkFormatStringExpr( | 
 |           S, ReferenceFormatString, SLE, Args, APK, format_idx, firstDataArg, | 
 |           Type, CallType, /*InFunctionCall*/ false, CheckedVarArgs, | 
 |           UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 |   case Stmt::ObjCMessageExprClass: { | 
 |     const auto *ME = cast<ObjCMessageExpr>(E); | 
 |     if (const auto *MD = ME->getMethodDecl()) { | 
 |       if (const auto *FA = MD->getAttr<FormatArgAttr>()) { | 
 |         // As a special case heuristic, if we're using the method -[NSBundle | 
 |         // localizedStringForKey:value:table:], ignore any key strings that lack | 
 |         // format specifiers. The idea is that if the key doesn't have any | 
 |         // format specifiers then its probably just a key to map to the | 
 |         // localized strings. If it does have format specifiers though, then its | 
 |         // likely that the text of the key is the format string in the | 
 |         // programmer's language, and should be checked. | 
 |         const ObjCInterfaceDecl *IFace; | 
 |         if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) && | 
 |             IFace->getIdentifier()->isStr("NSBundle") && | 
 |             MD->getSelector().isKeywordSelector( | 
 |                 {"localizedStringForKey", "value", "table"})) { | 
 |           IgnoreStringsWithoutSpecifiers = true; | 
 |         } | 
 |  | 
 |         const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); | 
 |         return checkFormatStringExpr( | 
 |             S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg, | 
 |             Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, | 
 |             Offset, IgnoreStringsWithoutSpecifiers); | 
 |       } | 
 |     } | 
 |  | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 |   case Stmt::ObjCStringLiteralClass: | 
 |   case Stmt::StringLiteralClass: { | 
 |     const StringLiteral *StrE = nullptr; | 
 |  | 
 |     if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E)) | 
 |       StrE = ObjCFExpr->getString(); | 
 |     else | 
 |       StrE = cast<StringLiteral>(E); | 
 |  | 
 |     if (StrE) { | 
 |       if (Offset.isNegative() || Offset > StrE->getLength()) { | 
 |         // TODO: It would be better to have an explicit warning for out of | 
 |         // bounds literals. | 
 |         return SLCT_NotALiteral; | 
 |       } | 
 |       FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue()); | 
 |       CheckFormatString(S, &FStr, ReferenceFormatString, E, Args, APK, | 
 |                         format_idx, firstDataArg, Type, InFunctionCall, | 
 |                         CallType, CheckedVarArgs, UncoveredArg, | 
 |                         IgnoreStringsWithoutSpecifiers); | 
 |       return SLCT_CheckedLiteral; | 
 |     } | 
 |  | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 |   case Stmt::BinaryOperatorClass: { | 
 |     const BinaryOperator *BinOp = cast<BinaryOperator>(E); | 
 |  | 
 |     // A string literal + an int offset is still a string literal. | 
 |     if (BinOp->isAdditiveOp()) { | 
 |       Expr::EvalResult LResult, RResult; | 
 |  | 
 |       bool LIsInt = BinOp->getLHS()->EvaluateAsInt( | 
 |           LResult, S.Context, Expr::SE_NoSideEffects, | 
 |           S.isConstantEvaluatedContext()); | 
 |       bool RIsInt = BinOp->getRHS()->EvaluateAsInt( | 
 |           RResult, S.Context, Expr::SE_NoSideEffects, | 
 |           S.isConstantEvaluatedContext()); | 
 |  | 
 |       if (LIsInt != RIsInt) { | 
 |         BinaryOperatorKind BinOpKind = BinOp->getOpcode(); | 
 |  | 
 |         if (LIsInt) { | 
 |           if (BinOpKind == BO_Add) { | 
 |             sumOffsets(Offset, LResult.Val.getInt(), BinOpKind, RIsInt); | 
 |             E = BinOp->getRHS(); | 
 |             goto tryAgain; | 
 |           } | 
 |         } else { | 
 |           sumOffsets(Offset, RResult.Val.getInt(), BinOpKind, RIsInt); | 
 |           E = BinOp->getLHS(); | 
 |           goto tryAgain; | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 |   case Stmt::UnaryOperatorClass: { | 
 |     const UnaryOperator *UnaOp = cast<UnaryOperator>(E); | 
 |     auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr()); | 
 |     if (UnaOp->getOpcode() == UO_AddrOf && ASE) { | 
 |       Expr::EvalResult IndexResult; | 
 |       if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context, | 
 |                                        Expr::SE_NoSideEffects, | 
 |                                        S.isConstantEvaluatedContext())) { | 
 |         sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add, | 
 |                    /*RHS is int*/ true); | 
 |         E = ASE->getBase(); | 
 |         goto tryAgain; | 
 |       } | 
 |     } | 
 |  | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 |  | 
 |   default: | 
 |     return SLCT_NotALiteral; | 
 |   } | 
 | } | 
 |  | 
 | // If this expression can be evaluated at compile-time, | 
 | // check if the result is a StringLiteral and return it | 
 | // otherwise return nullptr | 
 | static const Expr *maybeConstEvalStringLiteral(ASTContext &Context, | 
 |                                                const Expr *E) { | 
 |   Expr::EvalResult Result; | 
 |   if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) { | 
 |     const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>(); | 
 |     if (isa_and_nonnull<StringLiteral>(LVE)) | 
 |       return LVE; | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | StringRef Sema::GetFormatStringTypeName(FormatStringType FST) { | 
 |   switch (FST) { | 
 |   case FormatStringType::Scanf: | 
 |     return "scanf"; | 
 |   case FormatStringType::Printf: | 
 |     return "printf"; | 
 |   case FormatStringType::NSString: | 
 |     return "NSString"; | 
 |   case FormatStringType::Strftime: | 
 |     return "strftime"; | 
 |   case FormatStringType::Strfmon: | 
 |     return "strfmon"; | 
 |   case FormatStringType::Kprintf: | 
 |     return "kprintf"; | 
 |   case FormatStringType::FreeBSDKPrintf: | 
 |     return "freebsd_kprintf"; | 
 |   case FormatStringType::OSLog: | 
 |     return "os_log"; | 
 |   default: | 
 |     return "<unknown>"; | 
 |   } | 
 | } | 
 |  | 
 | FormatStringType Sema::GetFormatStringType(StringRef Flavor) { | 
 |   return llvm::StringSwitch<FormatStringType>(Flavor) | 
 |       .Cases("gnu_scanf", "scanf", FormatStringType::Scanf) | 
 |       .Cases("gnu_printf", "printf", "printf0", "syslog", | 
 |              FormatStringType::Printf) | 
 |       .Cases("NSString", "CFString", FormatStringType::NSString) | 
 |       .Cases("gnu_strftime", "strftime", FormatStringType::Strftime) | 
 |       .Cases("gnu_strfmon", "strfmon", FormatStringType::Strfmon) | 
 |       .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", | 
 |              FormatStringType::Kprintf) | 
 |       .Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf) | 
 |       .Case("os_trace", FormatStringType::OSLog) | 
 |       .Case("os_log", FormatStringType::OSLog) | 
 |       .Default(FormatStringType::Unknown); | 
 | } | 
 |  | 
 | FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { | 
 |   return GetFormatStringType(Format->getType()->getName()); | 
 | } | 
 |  | 
 | FormatStringType Sema::GetFormatStringType(const FormatMatchesAttr *Format) { | 
 |   return GetFormatStringType(Format->getType()->getName()); | 
 | } | 
 |  | 
 | bool Sema::CheckFormatArguments(const FormatAttr *Format, | 
 |                                 ArrayRef<const Expr *> Args, bool IsCXXMember, | 
 |                                 VariadicCallType CallType, SourceLocation Loc, | 
 |                                 SourceRange Range, | 
 |                                 llvm::SmallBitVector &CheckedVarArgs) { | 
 |   FormatStringInfo FSI; | 
 |   if (getFormatStringInfo(Format->getFormatIdx(), Format->getFirstArg(), | 
 |                           IsCXXMember, | 
 |                           CallType != VariadicCallType::DoesNotApply, &FSI)) | 
 |     return CheckFormatArguments( | 
 |         Args, FSI.ArgPassingKind, nullptr, FSI.FormatIdx, FSI.FirstDataArg, | 
 |         GetFormatStringType(Format), CallType, Loc, Range, CheckedVarArgs); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::CheckFormatString(const FormatMatchesAttr *Format, | 
 |                              ArrayRef<const Expr *> Args, bool IsCXXMember, | 
 |                              VariadicCallType CallType, SourceLocation Loc, | 
 |                              SourceRange Range, | 
 |                              llvm::SmallBitVector &CheckedVarArgs) { | 
 |   FormatStringInfo FSI; | 
 |   if (getFormatStringInfo(Format->getFormatIdx(), 0, IsCXXMember, false, | 
 |                           &FSI)) { | 
 |     FSI.ArgPassingKind = Sema::FAPK_Elsewhere; | 
 |     return CheckFormatArguments(Args, FSI.ArgPassingKind, | 
 |                                 Format->getFormatString(), FSI.FormatIdx, | 
 |                                 FSI.FirstDataArg, GetFormatStringType(Format), | 
 |                                 CallType, Loc, Range, CheckedVarArgs); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, | 
 |                                 Sema::FormatArgumentPassingKind APK, | 
 |                                 const StringLiteral *ReferenceFormatString, | 
 |                                 unsigned format_idx, unsigned firstDataArg, | 
 |                                 FormatStringType Type, | 
 |                                 VariadicCallType CallType, SourceLocation Loc, | 
 |                                 SourceRange Range, | 
 |                                 llvm::SmallBitVector &CheckedVarArgs) { | 
 |   // CHECK: printf/scanf-like function is called with no format string. | 
 |   if (format_idx >= Args.size()) { | 
 |     Diag(Loc, diag::warn_missing_format_string) << Range; | 
 |     return false; | 
 |   } | 
 |  | 
 |   const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts(); | 
 |  | 
 |   // CHECK: format string is not a string literal. | 
 |   // | 
 |   // Dynamically generated format strings are difficult to | 
 |   // automatically vet at compile time.  Requiring that format strings | 
 |   // are string literals: (1) permits the checking of format strings by | 
 |   // the compiler and thereby (2) can practically remove the source of | 
 |   // many format string exploits. | 
 |  | 
 |   // Format string can be either ObjC string (e.g. @"%d") or | 
 |   // C string (e.g. "%d") | 
 |   // ObjC string uses the same format specifiers as C string, so we can use | 
 |   // the same format string checking logic for both ObjC and C strings. | 
 |   UncoveredArgHandler UncoveredArg; | 
 |   StringLiteralCheckType CT = checkFormatStringExpr( | 
 |       *this, ReferenceFormatString, OrigFormatExpr, Args, APK, format_idx, | 
 |       firstDataArg, Type, CallType, | 
 |       /*IsFunctionCall*/ true, CheckedVarArgs, UncoveredArg, | 
 |       /*no string offset*/ llvm::APSInt(64, false) = 0); | 
 |  | 
 |   // Generate a diagnostic where an uncovered argument is detected. | 
 |   if (UncoveredArg.hasUncoveredArg()) { | 
 |     unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg; | 
 |     assert(ArgIdx < Args.size() && "ArgIdx outside bounds"); | 
 |     UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]); | 
 |   } | 
 |  | 
 |   if (CT != SLCT_NotALiteral) | 
 |     // Literal format string found, check done! | 
 |     return CT == SLCT_CheckedLiteral; | 
 |  | 
 |   // Strftime is particular as it always uses a single 'time' argument, | 
 |   // so it is safe to pass a non-literal string. | 
 |   if (Type == FormatStringType::Strftime) | 
 |     return false; | 
 |  | 
 |   // Do not emit diag when the string param is a macro expansion and the | 
 |   // format is either NSString or CFString. This is a hack to prevent | 
 |   // diag when using the NSLocalizedString and CFCopyLocalizedString macros | 
 |   // which are usually used in place of NS and CF string literals. | 
 |   SourceLocation FormatLoc = Args[format_idx]->getBeginLoc(); | 
 |   if (Type == FormatStringType::NSString && | 
 |       SourceMgr.isInSystemMacro(FormatLoc)) | 
 |     return false; | 
 |  | 
 |   // If there are no arguments specified, warn with -Wformat-security, otherwise | 
 |   // warn only with -Wformat-nonliteral. | 
 |   if (Args.size() == firstDataArg) { | 
 |     Diag(FormatLoc, diag::warn_format_nonliteral_noargs) | 
 |       << OrigFormatExpr->getSourceRange(); | 
 |     switch (Type) { | 
 |     default: | 
 |       break; | 
 |     case FormatStringType::Kprintf: | 
 |     case FormatStringType::FreeBSDKPrintf: | 
 |     case FormatStringType::Printf: | 
 |       Diag(FormatLoc, diag::note_format_security_fixit) | 
 |         << FixItHint::CreateInsertion(FormatLoc, "\"%s\", "); | 
 |       break; | 
 |     case FormatStringType::NSString: | 
 |       Diag(FormatLoc, diag::note_format_security_fixit) | 
 |         << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", "); | 
 |       break; | 
 |     } | 
 |   } else { | 
 |     Diag(FormatLoc, diag::warn_format_nonliteral) | 
 |       << OrigFormatExpr->getSourceRange(); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | class CheckFormatHandler : public analyze_format_string::FormatStringHandler { | 
 | protected: | 
 |   Sema &S; | 
 |   const FormatStringLiteral *FExpr; | 
 |   const Expr *OrigFormatExpr; | 
 |   const FormatStringType FSType; | 
 |   const unsigned FirstDataArg; | 
 |   const unsigned NumDataArgs; | 
 |   const char *Beg; // Start of format string. | 
 |   const Sema::FormatArgumentPassingKind ArgPassingKind; | 
 |   ArrayRef<const Expr *> Args; | 
 |   unsigned FormatIdx; | 
 |   llvm::SmallBitVector CoveredArgs; | 
 |   bool usesPositionalArgs = false; | 
 |   bool atFirstArg = true; | 
 |   bool inFunctionCall; | 
 |   VariadicCallType CallType; | 
 |   llvm::SmallBitVector &CheckedVarArgs; | 
 |   UncoveredArgHandler &UncoveredArg; | 
 |  | 
 | public: | 
 |   CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr, | 
 |                      const Expr *origFormatExpr, const FormatStringType type, | 
 |                      unsigned firstDataArg, unsigned numDataArgs, | 
 |                      const char *beg, Sema::FormatArgumentPassingKind APK, | 
 |                      ArrayRef<const Expr *> Args, unsigned formatIdx, | 
 |                      bool inFunctionCall, VariadicCallType callType, | 
 |                      llvm::SmallBitVector &CheckedVarArgs, | 
 |                      UncoveredArgHandler &UncoveredArg) | 
 |       : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type), | 
 |         FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), | 
 |         ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx), | 
 |         inFunctionCall(inFunctionCall), CallType(callType), | 
 |         CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { | 
 |     CoveredArgs.resize(numDataArgs); | 
 |     CoveredArgs.reset(); | 
 |   } | 
 |  | 
 |   bool HasFormatArguments() const { | 
 |     return ArgPassingKind == Sema::FAPK_Fixed || | 
 |            ArgPassingKind == Sema::FAPK_Variadic; | 
 |   } | 
 |  | 
 |   void DoneProcessing(); | 
 |  | 
 |   void HandleIncompleteSpecifier(const char *startSpecifier, | 
 |                                  unsigned specifierLen) override; | 
 |  | 
 |   void HandleInvalidLengthModifier( | 
 |                            const analyze_format_string::FormatSpecifier &FS, | 
 |                            const analyze_format_string::ConversionSpecifier &CS, | 
 |                            const char *startSpecifier, unsigned specifierLen, | 
 |                            unsigned DiagID); | 
 |  | 
 |   void HandleNonStandardLengthModifier( | 
 |                     const analyze_format_string::FormatSpecifier &FS, | 
 |                     const char *startSpecifier, unsigned specifierLen); | 
 |  | 
 |   void HandleNonStandardConversionSpecifier( | 
 |                     const analyze_format_string::ConversionSpecifier &CS, | 
 |                     const char *startSpecifier, unsigned specifierLen); | 
 |  | 
 |   void HandlePosition(const char *startPos, unsigned posLen) override; | 
 |  | 
 |   void HandleInvalidPosition(const char *startSpecifier, | 
 |                              unsigned specifierLen, | 
 |                              analyze_format_string::PositionContext p) override; | 
 |  | 
 |   void HandleZeroPosition(const char *startPos, unsigned posLen) override; | 
 |  | 
 |   void HandleNullChar(const char *nullCharacter) override; | 
 |  | 
 |   template <typename Range> | 
 |   static void | 
 |   EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr, | 
 |                        const PartialDiagnostic &PDiag, SourceLocation StringLoc, | 
 |                        bool IsStringLocation, Range StringRange, | 
 |                        ArrayRef<FixItHint> Fixit = {}); | 
 |  | 
 | protected: | 
 |   bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, | 
 |                                         const char *startSpec, | 
 |                                         unsigned specifierLen, | 
 |                                         const char *csStart, unsigned csLen); | 
 |  | 
 |   void HandlePositionalNonpositionalArgs(SourceLocation Loc, | 
 |                                          const char *startSpec, | 
 |                                          unsigned specifierLen); | 
 |  | 
 |   SourceRange getFormatStringRange(); | 
 |   CharSourceRange getSpecifierRange(const char *startSpecifier, | 
 |                                     unsigned specifierLen); | 
 |   SourceLocation getLocationOfByte(const char *x); | 
 |  | 
 |   const Expr *getDataArg(unsigned i) const; | 
 |  | 
 |   bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS, | 
 |                     const analyze_format_string::ConversionSpecifier &CS, | 
 |                     const char *startSpecifier, unsigned specifierLen, | 
 |                     unsigned argIndex); | 
 |  | 
 |   template <typename Range> | 
 |   void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, | 
 |                             bool IsStringLocation, Range StringRange, | 
 |                             ArrayRef<FixItHint> Fixit = {}); | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | SourceRange CheckFormatHandler::getFormatStringRange() { | 
 |   return OrigFormatExpr->getSourceRange(); | 
 | } | 
 |  | 
 | CharSourceRange CheckFormatHandler:: | 
 | getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { | 
 |   SourceLocation Start = getLocationOfByte(startSpecifier); | 
 |   SourceLocation End   = getLocationOfByte(startSpecifier + specifierLen - 1); | 
 |  | 
 |   // Advance the end SourceLocation by one due to half-open ranges. | 
 |   End = End.getLocWithOffset(1); | 
 |  | 
 |   return CharSourceRange::getCharRange(Start, End); | 
 | } | 
 |  | 
 | SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) { | 
 |   return FExpr->getLocationOfByte(x - Beg, S.getSourceManager(), | 
 |                                   S.getLangOpts(), S.Context.getTargetInfo()); | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier, | 
 |                                                    unsigned specifierLen){ | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_printf_incomplete_specifier), | 
 |                        getLocationOfByte(startSpecifier), | 
 |                        /*IsStringLocation*/true, | 
 |                        getSpecifierRange(startSpecifier, specifierLen)); | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleInvalidLengthModifier( | 
 |     const analyze_format_string::FormatSpecifier &FS, | 
 |     const analyze_format_string::ConversionSpecifier &CS, | 
 |     const char *startSpecifier, unsigned specifierLen, unsigned DiagID) { | 
 |   using namespace analyze_format_string; | 
 |  | 
 |   const LengthModifier &LM = FS.getLengthModifier(); | 
 |   CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); | 
 |  | 
 |   // See if we know how to fix this length modifier. | 
 |   std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); | 
 |   if (FixedLM) { | 
 |     EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), | 
 |                          getLocationOfByte(LM.getStart()), | 
 |                          /*IsStringLocation*/true, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |  | 
 |     S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier) | 
 |       << FixedLM->toString() | 
 |       << FixItHint::CreateReplacement(LMRange, FixedLM->toString()); | 
 |  | 
 |   } else { | 
 |     FixItHint Hint; | 
 |     if (DiagID == diag::warn_format_nonsensical_length) | 
 |       Hint = FixItHint::CreateRemoval(LMRange); | 
 |  | 
 |     EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), | 
 |                          getLocationOfByte(LM.getStart()), | 
 |                          /*IsStringLocation*/true, | 
 |                          getSpecifierRange(startSpecifier, specifierLen), | 
 |                          Hint); | 
 |   } | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleNonStandardLengthModifier( | 
 |     const analyze_format_string::FormatSpecifier &FS, | 
 |     const char *startSpecifier, unsigned specifierLen) { | 
 |   using namespace analyze_format_string; | 
 |  | 
 |   const LengthModifier &LM = FS.getLengthModifier(); | 
 |   CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); | 
 |  | 
 |   // See if we know how to fix this length modifier. | 
 |   std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); | 
 |   if (FixedLM) { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) | 
 |                            << LM.toString() << 0, | 
 |                          getLocationOfByte(LM.getStart()), | 
 |                          /*IsStringLocation*/true, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |  | 
 |     S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier) | 
 |       << FixedLM->toString() | 
 |       << FixItHint::CreateReplacement(LMRange, FixedLM->toString()); | 
 |  | 
 |   } else { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) | 
 |                            << LM.toString() << 0, | 
 |                          getLocationOfByte(LM.getStart()), | 
 |                          /*IsStringLocation*/true, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |   } | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleNonStandardConversionSpecifier( | 
 |     const analyze_format_string::ConversionSpecifier &CS, | 
 |     const char *startSpecifier, unsigned specifierLen) { | 
 |   using namespace analyze_format_string; | 
 |  | 
 |   // See if we know how to fix this conversion specifier. | 
 |   std::optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier(); | 
 |   if (FixedCS) { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) | 
 |                           << CS.toString() << /*conversion specifier*/1, | 
 |                          getLocationOfByte(CS.getStart()), | 
 |                          /*IsStringLocation*/true, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |  | 
 |     CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength()); | 
 |     S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier) | 
 |       << FixedCS->toString() | 
 |       << FixItHint::CreateReplacement(CSRange, FixedCS->toString()); | 
 |   } else { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) | 
 |                           << CS.toString() << /*conversion specifier*/1, | 
 |                          getLocationOfByte(CS.getStart()), | 
 |                          /*IsStringLocation*/true, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |   } | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandlePosition(const char *startPos, | 
 |                                         unsigned posLen) { | 
 |   if (!S.getDiagnostics().isIgnored( | 
 |           diag::warn_format_non_standard_positional_arg, SourceLocation())) | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg), | 
 |                          getLocationOfByte(startPos), | 
 |                          /*IsStringLocation*/ true, | 
 |                          getSpecifierRange(startPos, posLen)); | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleInvalidPosition( | 
 |     const char *startSpecifier, unsigned specifierLen, | 
 |     analyze_format_string::PositionContext p) { | 
 |   if (!S.getDiagnostics().isIgnored( | 
 |           diag::warn_format_invalid_positional_specifier, SourceLocation())) | 
 |     EmitFormatDiagnostic( | 
 |         S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned)p, | 
 |         getLocationOfByte(startSpecifier), /*IsStringLocation*/ true, | 
 |         getSpecifierRange(startSpecifier, specifierLen)); | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleZeroPosition(const char *startPos, | 
 |                                             unsigned posLen) { | 
 |   if (!S.getDiagnostics().isIgnored(diag::warn_format_zero_positional_specifier, | 
 |                                     SourceLocation())) | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier), | 
 |                          getLocationOfByte(startPos), | 
 |                          /*IsStringLocation*/ true, | 
 |                          getSpecifierRange(startPos, posLen)); | 
 | } | 
 |  | 
 | void CheckFormatHandler::HandleNullChar(const char *nullCharacter) { | 
 |   if (!isa<ObjCStringLiteral>(OrigFormatExpr)) { | 
 |     // The presence of a null character is likely an error. | 
 |     EmitFormatDiagnostic( | 
 |       S.PDiag(diag::warn_printf_format_string_contains_null_char), | 
 |       getLocationOfByte(nullCharacter), /*IsStringLocation*/true, | 
 |       getFormatStringRange()); | 
 |   } | 
 | } | 
 |  | 
 | // Note that this may return NULL if there was an error parsing or building | 
 | // one of the argument expressions. | 
 | const Expr *CheckFormatHandler::getDataArg(unsigned i) const { | 
 |   return Args[FirstDataArg + i]; | 
 | } | 
 |  | 
 | void CheckFormatHandler::DoneProcessing() { | 
 |   // Does the number of data arguments exceed the number of | 
 |   // format conversions in the format string? | 
 |   if (HasFormatArguments()) { | 
 |     // Find any arguments that weren't covered. | 
 |     CoveredArgs.flip(); | 
 |     signed notCoveredArg = CoveredArgs.find_first(); | 
 |     if (notCoveredArg >= 0) { | 
 |       assert((unsigned)notCoveredArg < NumDataArgs); | 
 |       UncoveredArg.Update(notCoveredArg, OrigFormatExpr); | 
 |     } else { | 
 |       UncoveredArg.setAllCovered(); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall, | 
 |                                    const Expr *ArgExpr) { | 
 |   assert(hasUncoveredArg() && !DiagnosticExprs.empty() && | 
 |          "Invalid state"); | 
 |  | 
 |   if (!ArgExpr) | 
 |     return; | 
 |  | 
 |   SourceLocation Loc = ArgExpr->getBeginLoc(); | 
 |  | 
 |   if (S.getSourceManager().isInSystemMacro(Loc)) | 
 |     return; | 
 |  | 
 |   PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used); | 
 |   for (auto E : DiagnosticExprs) | 
 |     PDiag << E->getSourceRange(); | 
 |  | 
 |   CheckFormatHandler::EmitFormatDiagnostic( | 
 |                                   S, IsFunctionCall, DiagnosticExprs[0], | 
 |                                   PDiag, Loc, /*IsStringLocation*/false, | 
 |                                   DiagnosticExprs[0]->getSourceRange()); | 
 | } | 
 |  | 
 | bool | 
 | CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, | 
 |                                                      SourceLocation Loc, | 
 |                                                      const char *startSpec, | 
 |                                                      unsigned specifierLen, | 
 |                                                      const char *csStart, | 
 |                                                      unsigned csLen) { | 
 |   bool keepGoing = true; | 
 |   if (argIndex < NumDataArgs) { | 
 |     // Consider the argument coverered, even though the specifier doesn't | 
 |     // make sense. | 
 |     CoveredArgs.set(argIndex); | 
 |   } | 
 |   else { | 
 |     // If argIndex exceeds the number of data arguments we | 
 |     // don't issue a warning because that is just a cascade of warnings (and | 
 |     // they may have intended '%%' anyway). We don't want to continue processing | 
 |     // the format string after this point, however, as we will like just get | 
 |     // gibberish when trying to match arguments. | 
 |     keepGoing = false; | 
 |   } | 
 |  | 
 |   StringRef Specifier(csStart, csLen); | 
 |  | 
 |   // If the specifier in non-printable, it could be the first byte of a UTF-8 | 
 |   // sequence. In that case, print the UTF-8 code point. If not, print the byte | 
 |   // hex value. | 
 |   std::string CodePointStr; | 
 |   if (!llvm::sys::locale::isPrint(*csStart)) { | 
 |     llvm::UTF32 CodePoint; | 
 |     const llvm::UTF8 **B = reinterpret_cast<const llvm::UTF8 **>(&csStart); | 
 |     const llvm::UTF8 *E = | 
 |         reinterpret_cast<const llvm::UTF8 *>(csStart + csLen); | 
 |     llvm::ConversionResult Result = | 
 |         llvm::convertUTF8Sequence(B, E, &CodePoint, llvm::strictConversion); | 
 |  | 
 |     if (Result != llvm::conversionOK) { | 
 |       unsigned char FirstChar = *csStart; | 
 |       CodePoint = (llvm::UTF32)FirstChar; | 
 |     } | 
 |  | 
 |     llvm::raw_string_ostream OS(CodePointStr); | 
 |     if (CodePoint < 256) | 
 |       OS << "\\x" << llvm::format("%02x", CodePoint); | 
 |     else if (CodePoint <= 0xFFFF) | 
 |       OS << "\\u" << llvm::format("%04x", CodePoint); | 
 |     else | 
 |       OS << "\\U" << llvm::format("%08x", CodePoint); | 
 |     Specifier = CodePointStr; | 
 |   } | 
 |  | 
 |   EmitFormatDiagnostic( | 
 |       S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc, | 
 |       /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen)); | 
 |  | 
 |   return keepGoing; | 
 | } | 
 |  | 
 | void | 
 | CheckFormatHandler::HandlePositionalNonpositionalArgs(SourceLocation Loc, | 
 |                                                       const char *startSpec, | 
 |                                                       unsigned specifierLen) { | 
 |   EmitFormatDiagnostic( | 
 |     S.PDiag(diag::warn_format_mix_positional_nonpositional_args), | 
 |     Loc, /*isStringLoc*/true, getSpecifierRange(startSpec, specifierLen)); | 
 | } | 
 |  | 
 | bool | 
 | CheckFormatHandler::CheckNumArgs( | 
 |   const analyze_format_string::FormatSpecifier &FS, | 
 |   const analyze_format_string::ConversionSpecifier &CS, | 
 |   const char *startSpecifier, unsigned specifierLen, unsigned argIndex) { | 
 |  | 
 |   if (HasFormatArguments() && argIndex >= NumDataArgs) { | 
 |     PartialDiagnostic PDiag = FS.usesPositionalArg() | 
 |       ? (S.PDiag(diag::warn_printf_positional_arg_exceeds_data_args) | 
 |            << (argIndex+1) << NumDataArgs) | 
 |       : S.PDiag(diag::warn_printf_insufficient_data_args); | 
 |     EmitFormatDiagnostic( | 
 |       PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true, | 
 |       getSpecifierRange(startSpecifier, specifierLen)); | 
 |  | 
 |     // Since more arguments than conversion tokens are given, by extension | 
 |     // all arguments are covered, so mark this as so. | 
 |     UncoveredArg.setAllCovered(); | 
 |     return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | template<typename Range> | 
 | void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, | 
 |                                               SourceLocation Loc, | 
 |                                               bool IsStringLocation, | 
 |                                               Range StringRange, | 
 |                                               ArrayRef<FixItHint> FixIt) { | 
 |   EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag, | 
 |                        Loc, IsStringLocation, StringRange, FixIt); | 
 | } | 
 |  | 
 | /// If the format string is not within the function call, emit a note | 
 | /// so that the function call and string are in diagnostic messages. | 
 | /// | 
 | /// \param InFunctionCall if true, the format string is within the function | 
 | /// call and only one diagnostic message will be produced.  Otherwise, an | 
 | /// extra note will be emitted pointing to location of the format string. | 
 | /// | 
 | /// \param ArgumentExpr the expression that is passed as the format string | 
 | /// argument in the function call.  Used for getting locations when two | 
 | /// diagnostics are emitted. | 
 | /// | 
 | /// \param PDiag the callee should already have provided any strings for the | 
 | /// diagnostic message.  This function only adds locations and fixits | 
 | /// to diagnostics. | 
 | /// | 
 | /// \param Loc primary location for diagnostic.  If two diagnostics are | 
 | /// required, one will be at Loc and a new SourceLocation will be created for | 
 | /// the other one. | 
 | /// | 
 | /// \param IsStringLocation if true, Loc points to the format string should be | 
 | /// used for the note.  Otherwise, Loc points to the argument list and will | 
 | /// be used with PDiag. | 
 | /// | 
 | /// \param StringRange some or all of the string to highlight.  This is | 
 | /// templated so it can accept either a CharSourceRange or a SourceRange. | 
 | /// | 
 | /// \param FixIt optional fix it hint for the format string. | 
 | template <typename Range> | 
 | void CheckFormatHandler::EmitFormatDiagnostic( | 
 |     Sema &S, bool InFunctionCall, const Expr *ArgumentExpr, | 
 |     const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation, | 
 |     Range StringRange, ArrayRef<FixItHint> FixIt) { | 
 |   if (InFunctionCall) { | 
 |     const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); | 
 |     D << StringRange; | 
 |     D << FixIt; | 
 |   } else { | 
 |     S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag) | 
 |       << ArgumentExpr->getSourceRange(); | 
 |  | 
 |     const Sema::SemaDiagnosticBuilder &Note = | 
 |       S.Diag(IsStringLocation ? Loc : StringRange.getBegin(), | 
 |              diag::note_format_string_defined); | 
 |  | 
 |     Note << StringRange; | 
 |     Note << FixIt; | 
 |   } | 
 | } | 
 |  | 
 | //===--- CHECK: Printf format string checking -----------------------------===// | 
 |  | 
 | namespace { | 
 |  | 
 | class CheckPrintfHandler : public CheckFormatHandler { | 
 | public: | 
 |   CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr, | 
 |                      const Expr *origFormatExpr, const FormatStringType type, | 
 |                      unsigned firstDataArg, unsigned numDataArgs, bool isObjC, | 
 |                      const char *beg, Sema::FormatArgumentPassingKind APK, | 
 |                      ArrayRef<const Expr *> Args, unsigned formatIdx, | 
 |                      bool inFunctionCall, VariadicCallType CallType, | 
 |                      llvm::SmallBitVector &CheckedVarArgs, | 
 |                      UncoveredArgHandler &UncoveredArg) | 
 |       : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, | 
 |                            numDataArgs, beg, APK, Args, formatIdx, | 
 |                            inFunctionCall, CallType, CheckedVarArgs, | 
 |                            UncoveredArg) {} | 
 |  | 
 |   bool isObjCContext() const { return FSType == FormatStringType::NSString; } | 
 |  | 
 |   /// Returns true if '%@' specifiers are allowed in the format string. | 
 |   bool allowsObjCArg() const { | 
 |     return FSType == FormatStringType::NSString || | 
 |            FSType == FormatStringType::OSLog || | 
 |            FSType == FormatStringType::OSTrace; | 
 |   } | 
 |  | 
 |   bool HandleInvalidPrintfConversionSpecifier( | 
 |                                       const analyze_printf::PrintfSpecifier &FS, | 
 |                                       const char *startSpecifier, | 
 |                                       unsigned specifierLen) override; | 
 |  | 
 |   void handleInvalidMaskType(StringRef MaskType) override; | 
 |  | 
 |   bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, | 
 |                              const char *startSpecifier, unsigned specifierLen, | 
 |                              const TargetInfo &Target) override; | 
 |   bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, | 
 |                        const char *StartSpecifier, | 
 |                        unsigned SpecifierLen, | 
 |                        const Expr *E); | 
 |  | 
 |   bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k, | 
 |                     const char *startSpecifier, unsigned specifierLen); | 
 |   void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS, | 
 |                            const analyze_printf::OptionalAmount &Amt, | 
 |                            unsigned type, | 
 |                            const char *startSpecifier, unsigned specifierLen); | 
 |   void HandleFlag(const analyze_printf::PrintfSpecifier &FS, | 
 |                   const analyze_printf::OptionalFlag &flag, | 
 |                   const char *startSpecifier, unsigned specifierLen); | 
 |   void HandleIgnoredFlag(const analyze_printf::PrintfSpecifier &FS, | 
 |                          const analyze_printf::OptionalFlag &ignoredFlag, | 
 |                          const analyze_printf::OptionalFlag &flag, | 
 |                          const char *startSpecifier, unsigned specifierLen); | 
 |   bool checkForCStrMembers(const analyze_printf::ArgType &AT, | 
 |                            const Expr *E); | 
 |  | 
 |   void HandleEmptyObjCModifierFlag(const char *startFlag, | 
 |                                    unsigned flagLen) override; | 
 |  | 
 |   void HandleInvalidObjCModifierFlag(const char *startFlag, | 
 |                                             unsigned flagLen) override; | 
 |  | 
 |   void | 
 |   HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, | 
 |                                        const char *flagsEnd, | 
 |                                        const char *conversionPosition) override; | 
 | }; | 
 |  | 
 | /// Keeps around the information needed to verify that two specifiers are | 
 | /// compatible. | 
 | class EquatableFormatArgument { | 
 | public: | 
 |   enum SpecifierSensitivity : unsigned { | 
 |     SS_None, | 
 |     SS_Private, | 
 |     SS_Public, | 
 |     SS_Sensitive | 
 |   }; | 
 |  | 
 |   enum FormatArgumentRole : unsigned { | 
 |     FAR_Data, | 
 |     FAR_FieldWidth, | 
 |     FAR_Precision, | 
 |     FAR_Auxiliary, // FreeBSD kernel %b and %D | 
 |   }; | 
 |  | 
 | private: | 
 |   analyze_format_string::ArgType ArgType; | 
 |   analyze_format_string::LengthModifier::Kind LengthMod; | 
 |   StringRef SpecifierLetter; | 
 |   CharSourceRange Range; | 
 |   SourceLocation ElementLoc; | 
 |   FormatArgumentRole Role : 2; | 
 |   SpecifierSensitivity Sensitivity : 2; // only set for FAR_Data | 
 |   unsigned Position : 14; | 
 |   unsigned ModifierFor : 14; // not set for FAR_Data | 
 |  | 
 |   void EmitDiagnostic(Sema &S, PartialDiagnostic PDiag, const Expr *FmtExpr, | 
 |                       bool InFunctionCall) const; | 
 |  | 
 | public: | 
 |   EquatableFormatArgument(CharSourceRange Range, SourceLocation ElementLoc, | 
 |                           analyze_format_string::LengthModifier::Kind LengthMod, | 
 |                           StringRef SpecifierLetter, | 
 |                           analyze_format_string::ArgType ArgType, | 
 |                           FormatArgumentRole Role, | 
 |                           SpecifierSensitivity Sensitivity, unsigned Position, | 
 |                           unsigned ModifierFor) | 
 |       : ArgType(ArgType), LengthMod(LengthMod), | 
 |         SpecifierLetter(SpecifierLetter), Range(Range), ElementLoc(ElementLoc), | 
 |         Role(Role), Sensitivity(Sensitivity), Position(Position), | 
 |         ModifierFor(ModifierFor) {} | 
 |  | 
 |   unsigned getPosition() const { return Position; } | 
 |   SourceLocation getSourceLocation() const { return ElementLoc; } | 
 |   CharSourceRange getSourceRange() const { return Range; } | 
 |   analyze_format_string::LengthModifier getLengthModifier() const { | 
 |     return analyze_format_string::LengthModifier(nullptr, LengthMod); | 
 |   } | 
 |   void setModifierFor(unsigned V) { ModifierFor = V; } | 
 |  | 
 |   std::string buildFormatSpecifier() const { | 
 |     std::string result; | 
 |     llvm::raw_string_ostream(result) | 
 |         << getLengthModifier().toString() << SpecifierLetter; | 
 |     return result; | 
 |   } | 
 |  | 
 |   bool VerifyCompatible(Sema &S, const EquatableFormatArgument &Other, | 
 |                         const Expr *FmtExpr, bool InFunctionCall) const; | 
 | }; | 
 |  | 
 | /// Turns format strings into lists of EquatableSpecifier objects. | 
 | class DecomposePrintfHandler : public CheckPrintfHandler { | 
 |   llvm::SmallVectorImpl<EquatableFormatArgument> &Specs; | 
 |   bool HadError; | 
 |  | 
 |   DecomposePrintfHandler(Sema &s, const FormatStringLiteral *fexpr, | 
 |                          const Expr *origFormatExpr, | 
 |                          const FormatStringType type, unsigned firstDataArg, | 
 |                          unsigned numDataArgs, bool isObjC, const char *beg, | 
 |                          Sema::FormatArgumentPassingKind APK, | 
 |                          ArrayRef<const Expr *> Args, unsigned formatIdx, | 
 |                          bool inFunctionCall, VariadicCallType CallType, | 
 |                          llvm::SmallBitVector &CheckedVarArgs, | 
 |                          UncoveredArgHandler &UncoveredArg, | 
 |                          llvm::SmallVectorImpl<EquatableFormatArgument> &Specs) | 
 |       : CheckPrintfHandler(s, fexpr, origFormatExpr, type, firstDataArg, | 
 |                            numDataArgs, isObjC, beg, APK, Args, formatIdx, | 
 |                            inFunctionCall, CallType, CheckedVarArgs, | 
 |                            UncoveredArg), | 
 |         Specs(Specs), HadError(false) {} | 
 |  | 
 | public: | 
 |   static bool | 
 |   GetSpecifiers(Sema &S, const FormatStringLiteral *FSL, const Expr *FmtExpr, | 
 |                 FormatStringType type, bool IsObjC, bool InFunctionCall, | 
 |                 llvm::SmallVectorImpl<EquatableFormatArgument> &Args); | 
 |  | 
 |   virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, | 
 |                                      const char *startSpecifier, | 
 |                                      unsigned specifierLen, | 
 |                                      const TargetInfo &Target) override; | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( | 
 |     const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, | 
 |     unsigned specifierLen) { | 
 |   const analyze_printf::PrintfConversionSpecifier &CS = | 
 |     FS.getConversionSpecifier(); | 
 |  | 
 |   return HandleInvalidConversionSpecifier(FS.getArgIndex(), | 
 |                                           getLocationOfByte(CS.getStart()), | 
 |                                           startSpecifier, specifierLen, | 
 |                                           CS.getStart(), CS.getLength()); | 
 | } | 
 |  | 
 | void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) { | 
 |   S.Diag(getLocationOfByte(MaskType.data()), diag::err_invalid_mask_type_size); | 
 | } | 
 |  | 
 | // Error out if struct or complex type argments are passed to os_log. | 
 | static bool isInvalidOSLogArgTypeForCodeGen(FormatStringType FSType, | 
 |                                             QualType T) { | 
 |   if (FSType != FormatStringType::OSLog) | 
 |     return false; | 
 |   return T->isRecordType() || T->isComplexType(); | 
 | } | 
 |  | 
 | bool CheckPrintfHandler::HandleAmount( | 
 |     const analyze_format_string::OptionalAmount &Amt, unsigned k, | 
 |     const char *startSpecifier, unsigned specifierLen) { | 
 |   if (Amt.hasDataArgument()) { | 
 |     if (HasFormatArguments()) { | 
 |       unsigned argIndex = Amt.getArgIndex(); | 
 |       if (argIndex >= NumDataArgs) { | 
 |         EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg) | 
 |                                  << k, | 
 |                              getLocationOfByte(Amt.getStart()), | 
 |                              /*IsStringLocation*/ true, | 
 |                              getSpecifierRange(startSpecifier, specifierLen)); | 
 |         // Don't do any more checking.  We will just emit | 
 |         // spurious errors. | 
 |         return false; | 
 |       } | 
 |  | 
 |       // Type check the data argument.  It should be an 'int'. | 
 |       // Although not in conformance with C99, we also allow the argument to be | 
 |       // an 'unsigned int' as that is a reasonably safe case.  GCC also | 
 |       // doesn't emit a warning for that case. | 
 |       CoveredArgs.set(argIndex); | 
 |       const Expr *Arg = getDataArg(argIndex); | 
 |       if (!Arg) | 
 |         return false; | 
 |  | 
 |       QualType T = Arg->getType(); | 
 |  | 
 |       const analyze_printf::ArgType &AT = Amt.getArgType(S.Context); | 
 |       assert(AT.isValid()); | 
 |  | 
 |       if (!AT.matchesType(S.Context, T)) { | 
 |         unsigned DiagID = isInvalidOSLogArgTypeForCodeGen(FSType, T) | 
 |                               ? diag::err_printf_asterisk_wrong_type | 
 |                               : diag::warn_printf_asterisk_wrong_type; | 
 |         EmitFormatDiagnostic(S.PDiag(DiagID) | 
 |                                  << k << AT.getRepresentativeTypeName(S.Context) | 
 |                                  << T << Arg->getSourceRange(), | 
 |                              getLocationOfByte(Amt.getStart()), | 
 |                              /*IsStringLocation*/ true, | 
 |                              getSpecifierRange(startSpecifier, specifierLen)); | 
 |         // Don't do any more checking.  We will just emit | 
 |         // spurious errors. | 
 |         return false; | 
 |       } | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void CheckPrintfHandler::HandleInvalidAmount( | 
 |                                       const analyze_printf::PrintfSpecifier &FS, | 
 |                                       const analyze_printf::OptionalAmount &Amt, | 
 |                                       unsigned type, | 
 |                                       const char *startSpecifier, | 
 |                                       unsigned specifierLen) { | 
 |   const analyze_printf::PrintfConversionSpecifier &CS = | 
 |     FS.getConversionSpecifier(); | 
 |  | 
 |   FixItHint fixit = | 
 |     Amt.getHowSpecified() == analyze_printf::OptionalAmount::Constant | 
 |       ? FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(), | 
 |                                  Amt.getConstantLength())) | 
 |       : FixItHint(); | 
 |  | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_optional_amount) | 
 |                          << type << CS.toString(), | 
 |                        getLocationOfByte(Amt.getStart()), | 
 |                        /*IsStringLocation*/true, | 
 |                        getSpecifierRange(startSpecifier, specifierLen), | 
 |                        fixit); | 
 | } | 
 |  | 
 | void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS, | 
 |                                     const analyze_printf::OptionalFlag &flag, | 
 |                                     const char *startSpecifier, | 
 |                                     unsigned specifierLen) { | 
 |   // Warn about pointless flag with a fixit removal. | 
 |   const analyze_printf::PrintfConversionSpecifier &CS = | 
 |     FS.getConversionSpecifier(); | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_flag) | 
 |                          << flag.toString() << CS.toString(), | 
 |                        getLocationOfByte(flag.getPosition()), | 
 |                        /*IsStringLocation*/true, | 
 |                        getSpecifierRange(startSpecifier, specifierLen), | 
 |                        FixItHint::CreateRemoval( | 
 |                          getSpecifierRange(flag.getPosition(), 1))); | 
 | } | 
 |  | 
 | void CheckPrintfHandler::HandleIgnoredFlag( | 
 |                                 const analyze_printf::PrintfSpecifier &FS, | 
 |                                 const analyze_printf::OptionalFlag &ignoredFlag, | 
 |                                 const analyze_printf::OptionalFlag &flag, | 
 |                                 const char *startSpecifier, | 
 |                                 unsigned specifierLen) { | 
 |   // Warn about ignored flag with a fixit removal. | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_printf_ignored_flag) | 
 |                          << ignoredFlag.toString() << flag.toString(), | 
 |                        getLocationOfByte(ignoredFlag.getPosition()), | 
 |                        /*IsStringLocation*/true, | 
 |                        getSpecifierRange(startSpecifier, specifierLen), | 
 |                        FixItHint::CreateRemoval( | 
 |                          getSpecifierRange(ignoredFlag.getPosition(), 1))); | 
 | } | 
 |  | 
 | void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag, | 
 |                                                      unsigned flagLen) { | 
 |   // Warn about an empty flag. | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_printf_empty_objc_flag), | 
 |                        getLocationOfByte(startFlag), | 
 |                        /*IsStringLocation*/true, | 
 |                        getSpecifierRange(startFlag, flagLen)); | 
 | } | 
 |  | 
 | void CheckPrintfHandler::HandleInvalidObjCModifierFlag(const char *startFlag, | 
 |                                                        unsigned flagLen) { | 
 |   // Warn about an invalid flag. | 
 |   auto Range = getSpecifierRange(startFlag, flagLen); | 
 |   StringRef flag(startFlag, flagLen); | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_printf_invalid_objc_flag) << flag, | 
 |                       getLocationOfByte(startFlag), | 
 |                       /*IsStringLocation*/true, | 
 |                       Range, FixItHint::CreateRemoval(Range)); | 
 | } | 
 |  | 
 | void CheckPrintfHandler::HandleObjCFlagsWithNonObjCConversion( | 
 |     const char *flagsStart, const char *flagsEnd, const char *conversionPosition) { | 
 |     // Warn about using '[...]' without a '@' conversion. | 
 |     auto Range = getSpecifierRange(flagsStart, flagsEnd - flagsStart + 1); | 
 |     auto diag = diag::warn_printf_ObjCflags_without_ObjCConversion; | 
 |     EmitFormatDiagnostic(S.PDiag(diag) << StringRef(conversionPosition, 1), | 
 |                          getLocationOfByte(conversionPosition), | 
 |                          /*IsStringLocation*/ true, Range, | 
 |                          FixItHint::CreateRemoval(Range)); | 
 | } | 
 |  | 
 | void EquatableFormatArgument::EmitDiagnostic(Sema &S, PartialDiagnostic PDiag, | 
 |                                              const Expr *FmtExpr, | 
 |                                              bool InFunctionCall) const { | 
 |   CheckFormatHandler::EmitFormatDiagnostic(S, InFunctionCall, FmtExpr, PDiag, | 
 |                                            ElementLoc, true, Range); | 
 | } | 
 |  | 
 | bool EquatableFormatArgument::VerifyCompatible( | 
 |     Sema &S, const EquatableFormatArgument &Other, const Expr *FmtExpr, | 
 |     bool InFunctionCall) const { | 
 |   using MK = analyze_format_string::ArgType::MatchKind; | 
 |   if (Role != Other.Role) { | 
 |     // diagnose and stop | 
 |     EmitDiagnostic( | 
 |         S, S.PDiag(diag::warn_format_cmp_role_mismatch) << Role << Other.Role, | 
 |         FmtExpr, InFunctionCall); | 
 |     S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range; | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (Role != FAR_Data) { | 
 |     if (ModifierFor != Other.ModifierFor) { | 
 |       // diagnose and stop | 
 |       EmitDiagnostic(S, | 
 |                      S.PDiag(diag::warn_format_cmp_modifierfor_mismatch) | 
 |                          << (ModifierFor + 1) << (Other.ModifierFor + 1), | 
 |                      FmtExpr, InFunctionCall); | 
 |       S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range; | 
 |       return false; | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |   bool HadError = false; | 
 |   if (Sensitivity != Other.Sensitivity) { | 
 |     // diagnose and continue | 
 |     EmitDiagnostic(S, | 
 |                    S.PDiag(diag::warn_format_cmp_sensitivity_mismatch) | 
 |                        << Sensitivity << Other.Sensitivity, | 
 |                    FmtExpr, InFunctionCall); | 
 |     HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with) | 
 |                << 0 << Other.Range; | 
 |   } | 
 |  | 
 |   switch (ArgType.matchesArgType(S.Context, Other.ArgType)) { | 
 |   case MK::Match: | 
 |     break; | 
 |  | 
 |   case MK::MatchPromotion: | 
 |     // Per consensus reached at https://discourse.llvm.org/t/-/83076/12, | 
 |     // MatchPromotion is treated as a failure by format_matches. | 
 |   case MK::NoMatch: | 
 |   case MK::NoMatchTypeConfusion: | 
 |   case MK::NoMatchPromotionTypeConfusion: | 
 |     EmitDiagnostic(S, | 
 |                    S.PDiag(diag::warn_format_cmp_specifier_mismatch) | 
 |                        << buildFormatSpecifier() | 
 |                        << Other.buildFormatSpecifier(), | 
 |                    FmtExpr, InFunctionCall); | 
 |     HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with) | 
 |                << 0 << Other.Range; | 
 |     break; | 
 |  | 
 |   case MK::NoMatchPedantic: | 
 |     EmitDiagnostic(S, | 
 |                    S.PDiag(diag::warn_format_cmp_specifier_mismatch_pedantic) | 
 |                        << buildFormatSpecifier() | 
 |                        << Other.buildFormatSpecifier(), | 
 |                    FmtExpr, InFunctionCall); | 
 |     HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with) | 
 |                << 0 << Other.Range; | 
 |     break; | 
 |  | 
 |   case MK::NoMatchSignedness: | 
 |     EmitDiagnostic(S, | 
 |                    S.PDiag(diag::warn_format_cmp_specifier_sign_mismatch) | 
 |                        << buildFormatSpecifier() | 
 |                        << Other.buildFormatSpecifier(), | 
 |                    FmtExpr, InFunctionCall); | 
 |     HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with) | 
 |                << 0 << Other.Range; | 
 |     break; | 
 |   } | 
 |   return !HadError; | 
 | } | 
 |  | 
 | bool DecomposePrintfHandler::GetSpecifiers( | 
 |     Sema &S, const FormatStringLiteral *FSL, const Expr *FmtExpr, | 
 |     FormatStringType Type, bool IsObjC, bool InFunctionCall, | 
 |     llvm::SmallVectorImpl<EquatableFormatArgument> &Args) { | 
 |   StringRef Data = FSL->getString(); | 
 |   const char *Str = Data.data(); | 
 |   llvm::SmallBitVector BV; | 
 |   UncoveredArgHandler UA; | 
 |   const Expr *PrintfArgs[] = {FSL->getFormatString()}; | 
 |   DecomposePrintfHandler H(S, FSL, FSL->getFormatString(), Type, 0, 0, IsObjC, | 
 |                            Str, Sema::FAPK_Elsewhere, PrintfArgs, 0, | 
 |                            InFunctionCall, VariadicCallType::DoesNotApply, BV, | 
 |                            UA, Args); | 
 |  | 
 |   if (!analyze_format_string::ParsePrintfString( | 
 |           H, Str, Str + Data.size(), S.getLangOpts(), S.Context.getTargetInfo(), | 
 |           Type == FormatStringType::FreeBSDKPrintf)) | 
 |     H.DoneProcessing(); | 
 |   if (H.HadError) | 
 |     return false; | 
 |  | 
 |   llvm::stable_sort(Args, [](const EquatableFormatArgument &A, | 
 |                              const EquatableFormatArgument &B) { | 
 |     return A.getPosition() < B.getPosition(); | 
 |   }); | 
 |   return true; | 
 | } | 
 |  | 
 | bool DecomposePrintfHandler::HandlePrintfSpecifier( | 
 |     const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, | 
 |     unsigned specifierLen, const TargetInfo &Target) { | 
 |   if (!CheckPrintfHandler::HandlePrintfSpecifier(FS, startSpecifier, | 
 |                                                  specifierLen, Target)) { | 
 |     HadError = true; | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Do not add any specifiers to the list for %%. This is possibly incorrect | 
 |   // if using a precision/width with a data argument, but that combination is | 
 |   // meaningless and we wouldn't know which format to attach the | 
 |   // precision/width to. | 
 |   const auto &CS = FS.getConversionSpecifier(); | 
 |   if (CS.getKind() == analyze_format_string::ConversionSpecifier::PercentArg) | 
 |     return true; | 
 |  | 
 |   // have to patch these to have the right ModifierFor if they are used | 
 |   const unsigned Unset = ~0; | 
 |   unsigned FieldWidthIndex = Unset; | 
 |   unsigned PrecisionIndex = Unset; | 
 |  | 
 |   // field width? | 
 |   const auto &FieldWidth = FS.getFieldWidth(); | 
 |   if (!FieldWidth.isInvalid() && FieldWidth.hasDataArgument()) { | 
 |     FieldWidthIndex = Specs.size(); | 
 |     Specs.emplace_back(getSpecifierRange(startSpecifier, specifierLen), | 
 |                        getLocationOfByte(FieldWidth.getStart()), | 
 |                        analyze_format_string::LengthModifier::None, "*", | 
 |                        FieldWidth.getArgType(S.Context), | 
 |                        EquatableFormatArgument::FAR_FieldWidth, | 
 |                        EquatableFormatArgument::SS_None, | 
 |                        FieldWidth.usesPositionalArg() | 
 |                            ? FieldWidth.getPositionalArgIndex() - 1 | 
 |                            : FieldWidthIndex, | 
 |                        0); | 
 |   } | 
 |   // precision? | 
 |   const auto &Precision = FS.getPrecision(); | 
 |   if (!Precision.isInvalid() && Precision.hasDataArgument()) { | 
 |     PrecisionIndex = Specs.size(); | 
 |     Specs.emplace_back( | 
 |         getSpecifierRange(startSpecifier, specifierLen), | 
 |         getLocationOfByte(Precision.getStart()), | 
 |         analyze_format_string::LengthModifier::None, ".*", | 
 |         Precision.getArgType(S.Context), EquatableFormatArgument::FAR_Precision, | 
 |         EquatableFormatArgument::SS_None, | 
 |         Precision.usesPositionalArg() ? Precision.getPositionalArgIndex() - 1 | 
 |                                       : PrecisionIndex, | 
 |         0); | 
 |   } | 
 |  | 
 |   // this specifier | 
 |   unsigned SpecIndex = | 
 |       FS.usesPositionalArg() ? FS.getPositionalArgIndex() - 1 : Specs.size(); | 
 |   if (FieldWidthIndex != Unset) | 
 |     Specs[FieldWidthIndex].setModifierFor(SpecIndex); | 
 |   if (PrecisionIndex != Unset) | 
 |     Specs[PrecisionIndex].setModifierFor(SpecIndex); | 
 |  | 
 |   EquatableFormatArgument::SpecifierSensitivity Sensitivity; | 
 |   if (FS.isPrivate()) | 
 |     Sensitivity = EquatableFormatArgument::SS_Private; | 
 |   else if (FS.isPublic()) | 
 |     Sensitivity = EquatableFormatArgument::SS_Public; | 
 |   else if (FS.isSensitive()) | 
 |     Sensitivity = EquatableFormatArgument::SS_Sensitive; | 
 |   else | 
 |     Sensitivity = EquatableFormatArgument::SS_None; | 
 |  | 
 |   Specs.emplace_back( | 
 |       getSpecifierRange(startSpecifier, specifierLen), | 
 |       getLocationOfByte(CS.getStart()), FS.getLengthModifier().getKind(), | 
 |       CS.getCharacters(), FS.getArgType(S.Context, isObjCContext()), | 
 |       EquatableFormatArgument::FAR_Data, Sensitivity, SpecIndex, 0); | 
 |  | 
 |   // auxiliary argument? | 
 |   if (CS.getKind() == analyze_format_string::ConversionSpecifier::FreeBSDbArg || | 
 |       CS.getKind() == analyze_format_string::ConversionSpecifier::FreeBSDDArg) { | 
 |     Specs.emplace_back(getSpecifierRange(startSpecifier, specifierLen), | 
 |                        getLocationOfByte(CS.getStart()), | 
 |                        analyze_format_string::LengthModifier::None, | 
 |                        CS.getCharacters(), | 
 |                        analyze_format_string::ArgType::CStrTy, | 
 |                        EquatableFormatArgument::FAR_Auxiliary, Sensitivity, | 
 |                        SpecIndex + 1, SpecIndex); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | // Determines if the specified is a C++ class or struct containing | 
 | // a member with the specified name and kind (e.g. a CXXMethodDecl named | 
 | // "c_str()"). | 
 | template<typename MemberKind> | 
 | static llvm::SmallPtrSet<MemberKind*, 1> | 
 | CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { | 
 |   auto *RD = Ty->getAsCXXRecordDecl(); | 
 |   llvm::SmallPtrSet<MemberKind*, 1> Results; | 
 |  | 
 |   if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition())) | 
 |     return Results; | 
 |  | 
 |   LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(), | 
 |                  Sema::LookupMemberName); | 
 |   R.suppressDiagnostics(); | 
 |  | 
 |   // We just need to include all members of the right kind turned up by the | 
 |   // filter, at this point. | 
 |   if (S.LookupQualifiedName(R, RD)) | 
 |     for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { | 
 |       NamedDecl *decl = (*I)->getUnderlyingDecl(); | 
 |       if (MemberKind *FK = dyn_cast<MemberKind>(decl)) | 
 |         Results.insert(FK); | 
 |     } | 
 |   return Results; | 
 | } | 
 |  | 
 | /// Check if we could call '.c_str()' on an object. | 
 | /// | 
 | /// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't | 
 | /// allow the call, or if it would be ambiguous). | 
 | bool Sema::hasCStrMethod(const Expr *E) { | 
 |   using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>; | 
 |  | 
 |   MethodSet Results = | 
 |       CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType()); | 
 |   for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); | 
 |        MI != ME; ++MI) | 
 |     if ((*MI)->getMinRequiredArguments() == 0) | 
 |       return true; | 
 |   return false; | 
 | } | 
 |  | 
 | // Check if a (w)string was passed when a (w)char* was needed, and offer a | 
 | // better diagnostic if so. AT is assumed to be valid. | 
 | // Returns true when a c_str() conversion method is found. | 
 | bool CheckPrintfHandler::checkForCStrMembers( | 
 |     const analyze_printf::ArgType &AT, const Expr *E) { | 
 |   using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>; | 
 |  | 
 |   MethodSet Results = | 
 |       CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType()); | 
 |  | 
 |   for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); | 
 |        MI != ME; ++MI) { | 
 |     const CXXMethodDecl *Method = *MI; | 
 |     if (Method->getMinRequiredArguments() == 0 && | 
 |         AT.matchesType(S.Context, Method->getReturnType())) { | 
 |       // FIXME: Suggest parens if the expression needs them. | 
 |       SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc()); | 
 |       S.Diag(E->getBeginLoc(), diag::note_printf_c_str) | 
 |           << "c_str()" << FixItHint::CreateInsertion(EndLoc, ".c_str()"); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool CheckPrintfHandler::HandlePrintfSpecifier( | 
 |     const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, | 
 |     unsigned specifierLen, const TargetInfo &Target) { | 
 |   using namespace analyze_format_string; | 
 |   using namespace analyze_printf; | 
 |  | 
 |   const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); | 
 |  | 
 |   if (FS.consumesDataArgument()) { | 
 |     if (atFirstArg) { | 
 |         atFirstArg = false; | 
 |         usesPositionalArgs = FS.usesPositionalArg(); | 
 |     } | 
 |     else if (usesPositionalArgs != FS.usesPositionalArg()) { | 
 |       HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()), | 
 |                                         startSpecifier, specifierLen); | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |   // First check if the field width, precision, and conversion specifier | 
 |   // have matching data arguments. | 
 |   if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0, | 
 |                     startSpecifier, specifierLen)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (!HandleAmount(FS.getPrecision(), /* precision */ 1, | 
 |                     startSpecifier, specifierLen)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (!CS.consumesDataArgument()) { | 
 |     // FIXME: Technically specifying a precision or field width here | 
 |     // makes no sense.  Worth issuing a warning at some point. | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Consume the argument. | 
 |   unsigned argIndex = FS.getArgIndex(); | 
 |   if (argIndex < NumDataArgs) { | 
 |     // The check to see if the argIndex is valid will come later. | 
 |     // We set the bit here because we may exit early from this | 
 |     // function if we encounter some other error. | 
 |     CoveredArgs.set(argIndex); | 
 |   } | 
 |  | 
 |   // FreeBSD kernel extensions. | 
 |   if (CS.getKind() == ConversionSpecifier::FreeBSDbArg || | 
 |       CS.getKind() == ConversionSpecifier::FreeBSDDArg) { | 
 |     // We need at least two arguments. | 
 |     if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1)) | 
 |       return false; | 
 |  | 
 |     if (HasFormatArguments()) { | 
 |       // Claim the second argument. | 
 |       CoveredArgs.set(argIndex + 1); | 
 |  | 
 |       // Type check the first argument (int for %b, pointer for %D) | 
 |       const Expr *Ex = getDataArg(argIndex); | 
 |       const analyze_printf::ArgType &AT = | 
 |           (CS.getKind() == ConversionSpecifier::FreeBSDbArg) | 
 |               ? ArgType(S.Context.IntTy) | 
 |               : ArgType::CPointerTy; | 
 |       if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) | 
 |         EmitFormatDiagnostic( | 
 |             S.PDiag(diag::warn_format_conversion_argument_type_mismatch) | 
 |                 << AT.getRepresentativeTypeName(S.Context) << Ex->getType() | 
 |                 << false << Ex->getSourceRange(), | 
 |             Ex->getBeginLoc(), /*IsStringLocation*/ false, | 
 |             getSpecifierRange(startSpecifier, specifierLen)); | 
 |  | 
 |       // Type check the second argument (char * for both %b and %D) | 
 |       Ex = getDataArg(argIndex + 1); | 
 |       const analyze_printf::ArgType &AT2 = ArgType::CStrTy; | 
 |       if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType())) | 
 |         EmitFormatDiagnostic( | 
 |             S.PDiag(diag::warn_format_conversion_argument_type_mismatch) | 
 |                 << AT2.getRepresentativeTypeName(S.Context) << Ex->getType() | 
 |                 << false << Ex->getSourceRange(), | 
 |             Ex->getBeginLoc(), /*IsStringLocation*/ false, | 
 |             getSpecifierRange(startSpecifier, specifierLen)); | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Check for using an Objective-C specific conversion specifier | 
 |   // in a non-ObjC literal. | 
 |   if (!allowsObjCArg() && CS.isObjCArg()) { | 
 |     return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, | 
 |                                                   specifierLen); | 
 |   } | 
 |  | 
 |   // %P can only be used with os_log. | 
 |   if (FSType != FormatStringType::OSLog && | 
 |       CS.getKind() == ConversionSpecifier::PArg) { | 
 |     return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, | 
 |                                                   specifierLen); | 
 |   } | 
 |  | 
 |   // %n is not allowed with os_log. | 
 |   if (FSType == FormatStringType::OSLog && | 
 |       CS.getKind() == ConversionSpecifier::nArg) { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_os_log_format_narg), | 
 |                          getLocationOfByte(CS.getStart()), | 
 |                          /*IsStringLocation*/ false, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |  | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Only scalars are allowed for os_trace. | 
 |   if (FSType == FormatStringType::OSTrace && | 
 |       (CS.getKind() == ConversionSpecifier::PArg || | 
 |        CS.getKind() == ConversionSpecifier::sArg || | 
 |        CS.getKind() == ConversionSpecifier::ObjCObjArg)) { | 
 |     return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, | 
 |                                                   specifierLen); | 
 |   } | 
 |  | 
 |   // Check for use of public/private annotation outside of os_log(). | 
 |   if (FSType != FormatStringType::OSLog) { | 
 |     if (FS.isPublic().isSet()) { | 
 |       EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) | 
 |                                << "public", | 
 |                            getLocationOfByte(FS.isPublic().getPosition()), | 
 |                            /*IsStringLocation*/ false, | 
 |                            getSpecifierRange(startSpecifier, specifierLen)); | 
 |     } | 
 |     if (FS.isPrivate().isSet()) { | 
 |       EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) | 
 |                                << "private", | 
 |                            getLocationOfByte(FS.isPrivate().getPosition()), | 
 |                            /*IsStringLocation*/ false, | 
 |                            getSpecifierRange(startSpecifier, specifierLen)); | 
 |     } | 
 |   } | 
 |  | 
 |   const llvm::Triple &Triple = Target.getTriple(); | 
 |   if (CS.getKind() == ConversionSpecifier::nArg && | 
 |       (Triple.isAndroid() || Triple.isOSFuchsia())) { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_printf_narg_not_supported), | 
 |                          getLocationOfByte(CS.getStart()), | 
 |                          /*IsStringLocation*/ false, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |   } | 
 |  | 
 |   // Check for invalid use of field width | 
 |   if (!FS.hasValidFieldWidth()) { | 
 |     HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0, | 
 |         startSpecifier, specifierLen); | 
 |   } | 
 |  | 
 |   // Check for invalid use of precision | 
 |   if (!FS.hasValidPrecision()) { | 
 |     HandleInvalidAmount(FS, FS.getPrecision(), /* precision */ 1, | 
 |         startSpecifier, specifierLen); | 
 |   } | 
 |  | 
 |   // Precision is mandatory for %P specifier. | 
 |   if (CS.getKind() == ConversionSpecifier::PArg && | 
 |       FS.getPrecision().getHowSpecified() == OptionalAmount::NotSpecified) { | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_no_precision), | 
 |                          getLocationOfByte(startSpecifier), | 
 |                          /*IsStringLocation*/ false, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |   } | 
 |  | 
 |   // Check each flag does not conflict with any other component. | 
 |   if (!FS.hasValidThousandsGroupingPrefix()) | 
 |     HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen); | 
 |   if (!FS.hasValidLeadingZeros()) | 
 |     HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen); | 
 |   if (!FS.hasValidPlusPrefix()) | 
 |     HandleFlag(FS, FS.hasPlusPrefix(), startSpecifier, specifierLen); | 
 |   if (!FS.hasValidSpacePrefix()) | 
 |     HandleFlag(FS, FS.hasSpacePrefix(), startSpecifier, specifierLen); | 
 |   if (!FS.hasValidAlternativeForm()) | 
 |     HandleFlag(FS, FS.hasAlternativeForm(), startSpecifier, specifierLen); | 
 |   if (!FS.hasValidLeftJustified()) | 
 |     HandleFlag(FS, FS.isLeftJustified(), startSpecifier, specifierLen); | 
 |  | 
 |   // Check that flags are not ignored by another flag | 
 |   if (FS.hasSpacePrefix() && FS.hasPlusPrefix()) // ' ' ignored by '+' | 
 |     HandleIgnoredFlag(FS, FS.hasSpacePrefix(), FS.hasPlusPrefix(), | 
 |         startSpecifier, specifierLen); | 
 |   if (FS.hasLeadingZeros() && FS.isLeftJustified()) // '0' ignored by '-' | 
 |     HandleIgnoredFlag(FS, FS.hasLeadingZeros(), FS.isLeftJustified(), | 
 |             startSpecifier, specifierLen); | 
 |  | 
 |   // Check the length modifier is valid with the given conversion specifier. | 
 |   if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), | 
 |                                  S.getLangOpts())) | 
 |     HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, | 
 |                                 diag::warn_format_nonsensical_length); | 
 |   else if (!FS.hasStandardLengthModifier()) | 
 |     HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); | 
 |   else if (!FS.hasStandardLengthConversionCombination()) | 
 |     HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, | 
 |                                 diag::warn_format_non_standard_conversion_spec); | 
 |  | 
 |   if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) | 
 |     HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); | 
 |  | 
 |   // The remaining checks depend on the data arguments. | 
 |   if (!HasFormatArguments()) | 
 |     return true; | 
 |  | 
 |   if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) | 
 |     return false; | 
 |  | 
 |   const Expr *Arg = getDataArg(argIndex); | 
 |   if (!Arg) | 
 |     return true; | 
 |  | 
 |   return checkFormatExpr(FS, startSpecifier, specifierLen, Arg); | 
 | } | 
 |  | 
 | static bool requiresParensToAddCast(const Expr *E) { | 
 |   // FIXME: We should have a general way to reason about operator | 
 |   // precedence and whether parens are actually needed here. | 
 |   // Take care of a few common cases where they aren't. | 
 |   const Expr *Inside = E->IgnoreImpCasts(); | 
 |   if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(Inside)) | 
 |     Inside = POE->getSyntacticForm()->IgnoreImpCasts(); | 
 |  | 
 |   switch (Inside->getStmtClass()) { | 
 |   case Stmt::ArraySubscriptExprClass: | 
 |   case Stmt::CallExprClass: | 
 |   case Stmt::CharacterLiteralClass: | 
 |   case Stmt::CXXBoolLiteralExprClass: | 
 |   case Stmt::DeclRefExprClass: | 
 |   case Stmt::FloatingLiteralClass: | 
 |   case Stmt::IntegerLiteralClass: | 
 |   case Stmt::MemberExprClass: | 
 |   case Stmt::ObjCArrayLiteralClass: | 
 |   case Stmt::ObjCBoolLiteralExprClass: | 
 |   case Stmt::ObjCBoxedExprClass: | 
 |   case Stmt::ObjCDictionaryLiteralClass: | 
 |   case Stmt::ObjCEncodeExprClass: | 
 |   case Stmt::ObjCIvarRefExprClass: | 
 |   case Stmt::ObjCMessageExprClass: | 
 |   case Stmt::ObjCPropertyRefExprClass: | 
 |   case Stmt::ObjCStringLiteralClass: | 
 |   case Stmt::ObjCSubscriptRefExprClass: | 
 |   case Stmt::ParenExprClass: | 
 |   case Stmt::StringLiteralClass: | 
 |   case Stmt::UnaryOperatorClass: | 
 |     return false; | 
 |   default: | 
 |     return true; | 
 |   } | 
 | } | 
 |  | 
 | static std::pair<QualType, StringRef> | 
 | shouldNotPrintDirectly(const ASTContext &Context, | 
 |                        QualType IntendedTy, | 
 |                        const Expr *E) { | 
 |   // Use a 'while' to peel off layers of typedefs. | 
 |   QualType TyTy = IntendedTy; | 
 |   while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { | 
 |     StringRef Name = UserTy->getDecl()->getName(); | 
 |     QualType CastTy = llvm::StringSwitch<QualType>(Name) | 
 |       .Case("CFIndex", Context.getNSIntegerType()) | 
 |       .Case("NSInteger", Context.getNSIntegerType()) | 
 |       .Case("NSUInteger", Context.getNSUIntegerType()) | 
 |       .Case("SInt32", Context.IntTy) | 
 |       .Case("UInt32", Context.UnsignedIntTy) | 
 |       .Default(QualType()); | 
 |  | 
 |     if (!CastTy.isNull()) | 
 |       return std::make_pair(CastTy, Name); | 
 |  | 
 |     TyTy = UserTy->desugar(); | 
 |   } | 
 |  | 
 |   // Strip parens if necessary. | 
 |   if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) | 
 |     return shouldNotPrintDirectly(Context, | 
 |                                   PE->getSubExpr()->getType(), | 
 |                                   PE->getSubExpr()); | 
 |  | 
 |   // If this is a conditional expression, then its result type is constructed | 
 |   // via usual arithmetic conversions and thus there might be no necessary | 
 |   // typedef sugar there.  Recurse to operands to check for NSInteger & | 
 |   // Co. usage condition. | 
 |   if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { | 
 |     QualType TrueTy, FalseTy; | 
 |     StringRef TrueName, FalseName; | 
 |  | 
 |     std::tie(TrueTy, TrueName) = | 
 |       shouldNotPrintDirectly(Context, | 
 |                              CO->getTrueExpr()->getType(), | 
 |                              CO->getTrueExpr()); | 
 |     std::tie(FalseTy, FalseName) = | 
 |       shouldNotPrintDirectly(Context, | 
 |                              CO->getFalseExpr()->getType(), | 
 |                              CO->getFalseExpr()); | 
 |  | 
 |     if (TrueTy == FalseTy) | 
 |       return std::make_pair(TrueTy, TrueName); | 
 |     else if (TrueTy.isNull()) | 
 |       return std::make_pair(FalseTy, FalseName); | 
 |     else if (FalseTy.isNull()) | 
 |       return std::make_pair(TrueTy, TrueName); | 
 |   } | 
 |  | 
 |   return std::make_pair(QualType(), StringRef()); | 
 | } | 
 |  | 
 | /// Return true if \p ICE is an implicit argument promotion of an arithmetic | 
 | /// type. Bit-field 'promotions' from a higher ranked type to a lower ranked | 
 | /// type do not count. | 
 | static bool | 
 | isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) { | 
 |   QualType From = ICE->getSubExpr()->getType(); | 
 |   QualType To = ICE->getType(); | 
 |   // It's an integer promotion if the destination type is the promoted | 
 |   // source type. | 
 |   if (ICE->getCastKind() == CK_IntegralCast && | 
 |       S.Context.isPromotableIntegerType(From) && | 
 |       S.Context.getPromotedIntegerType(From) == To) | 
 |     return true; | 
 |   // Look through vector types, since we do default argument promotion for | 
 |   // those in OpenCL. | 
 |   if (const auto *VecTy = From->getAs<ExtVectorType>()) | 
 |     From = VecTy->getElementType(); | 
 |   if (const auto *VecTy = To->getAs<ExtVectorType>()) | 
 |     To = VecTy->getElementType(); | 
 |   // It's a floating promotion if the source type is a lower rank. | 
 |   return ICE->getCastKind() == CK_FloatingCast && | 
 |          S.Context.getFloatingTypeOrder(From, To) < 0; | 
 | } | 
 |  | 
 | static analyze_format_string::ArgType::MatchKind | 
 | handleFormatSignedness(analyze_format_string::ArgType::MatchKind Match, | 
 |                        DiagnosticsEngine &Diags, SourceLocation Loc) { | 
 |   if (Match == analyze_format_string::ArgType::NoMatchSignedness) { | 
 |     if (Diags.isIgnored( | 
 |             diag::warn_format_conversion_argument_type_mismatch_signedness, | 
 |             Loc) || | 
 |         Diags.isIgnored( | 
 |             // Arbitrary -Wformat diagnostic to detect -Wno-format: | 
 |             diag::warn_format_conversion_argument_type_mismatch, Loc)) { | 
 |       return analyze_format_string::ArgType::Match; | 
 |     } | 
 |   } | 
 |   return Match; | 
 | } | 
 |  | 
 | bool | 
 | CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, | 
 |                                     const char *StartSpecifier, | 
 |                                     unsigned SpecifierLen, | 
 |                                     const Expr *E) { | 
 |   using namespace analyze_format_string; | 
 |   using namespace analyze_printf; | 
 |  | 
 |   // Now type check the data expression that matches the | 
 |   // format specifier. | 
 |   const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext()); | 
 |   if (!AT.isValid()) | 
 |     return true; | 
 |  | 
 |   QualType ExprTy = E->getType(); | 
 |   while (const TypeOfExprType *TET = dyn_cast<TypeOfExprType>(ExprTy)) { | 
 |     ExprTy = TET->getUnderlyingExpr()->getType(); | 
 |   } | 
 |  | 
 |   // When using the format attribute in C++, you can receive a function or an | 
 |   // array that will necessarily decay to a pointer when passed to the final | 
 |   // format consumer. Apply decay before type comparison. | 
 |   if (ExprTy->canDecayToPointerType()) | 
 |     ExprTy = S.Context.getDecayedType(ExprTy); | 
 |  | 
 |   // Diagnose attempts to print a boolean value as a character. Unlike other | 
 |   // -Wformat diagnostics, this is fine from a type perspective, but it still | 
 |   // doesn't make sense. | 
 |   if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg && | 
 |       E->isKnownToHaveBooleanValue()) { | 
 |     const CharSourceRange &CSR = | 
 |         getSpecifierRange(StartSpecifier, SpecifierLen); | 
 |     SmallString<4> FSString; | 
 |     llvm::raw_svector_ostream os(FSString); | 
 |     FS.toString(os); | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character) | 
 |                              << FSString, | 
 |                          E->getExprLoc(), false, CSR); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Diagnose attempts to use '%P' with ObjC object types, which will result in | 
 |   // dumping raw class data (like is-a pointer), not actual data. | 
 |   if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::PArg && | 
 |       ExprTy->isObjCObjectPointerType()) { | 
 |     const CharSourceRange &CSR = | 
 |         getSpecifierRange(StartSpecifier, SpecifierLen); | 
 |     EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_with_objc_pointer), | 
 |                          E->getExprLoc(), false, CSR); | 
 |     return true; | 
 |   } | 
 |  | 
 |   ArgType::MatchKind ImplicitMatch = ArgType::NoMatch; | 
 |   ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); | 
 |   ArgType::MatchKind OrigMatch = Match; | 
 |  | 
 |   Match = handleFormatSignedness(Match, S.getDiagnostics(), E->getExprLoc()); | 
 |   if (Match == ArgType::Match) | 
 |     return true; | 
 |  | 
 |   // NoMatchPromotionTypeConfusion should be only returned in ImplictCastExpr | 
 |   assert(Match != ArgType::NoMatchPromotionTypeConfusion); | 
 |  | 
 |   // Look through argument promotions for our error message's reported type. | 
 |   // This includes the integral and floating promotions, but excludes array | 
 |   // and function pointer decay (seeing that an argument intended to be a | 
 |   // string has type 'char [6]' is probably more confusing than 'char *') and | 
 |   // certain bitfield promotions (bitfields can be 'demoted' to a lesser type). | 
 |   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { | 
 |     if (isArithmeticArgumentPromotion(S, ICE)) { | 
 |       E = ICE->getSubExpr(); | 
 |       ExprTy = E->getType(); | 
 |  | 
 |       // Check if we didn't match because of an implicit cast from a 'char' | 
 |       // or 'short' to an 'int'.  This is done because printf is a varargs | 
 |       // function. | 
 |       if (ICE->getType() == S.Context.IntTy || | 
 |           ICE->getType() == S.Context.UnsignedIntTy) { | 
 |         // All further checking is done on the subexpression | 
 |         ImplicitMatch = AT.matchesType(S.Context, ExprTy); | 
 |         if (OrigMatch == ArgType::NoMatchSignedness && | 
 |             ImplicitMatch != ArgType::NoMatchSignedness) | 
 |           // If the original match was a signedness match this match on the | 
 |           // implicit cast type also need to be signedness match otherwise we | 
 |           // might introduce new unexpected warnings from -Wformat-signedness. | 
 |           return true; | 
 |         ImplicitMatch = handleFormatSignedness( | 
 |             ImplicitMatch, S.getDiagnostics(), E->getExprLoc()); | 
 |         if (ImplicitMatch == ArgType::Match) | 
 |           return true; | 
 |       } | 
 |     } | 
 |   } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) { | 
 |     // Special case for 'a', which has type 'int' in C. | 
 |     // Note, however, that we do /not/ want to treat multibyte constants like | 
 |     // 'MooV' as characters! This form is deprecated but still exists. In | 
 |     // addition, don't treat expressions as of type 'char' if one byte length | 
 |     // modifier is provided. | 
 |     if (ExprTy == S.Context.IntTy && | 
 |         FS.getLengthModifier().getKind() != LengthModifier::AsChar) | 
 |       if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) { | 
 |         ExprTy = S.Context.CharTy; | 
 |         // To improve check results, we consider a character literal in C | 
 |         // to be a 'char' rather than an 'int'. 'printf("%hd", 'a');' is | 
 |         // more likely a type confusion situation, so we will suggest to | 
 |         // use '%hhd' instead by discarding the MatchPromotion. | 
 |         if (Match == ArgType::MatchPromotion) | 
 |           Match = ArgType::NoMatch; | 
 |       } | 
 |   } | 
 |   if (Match == ArgType::MatchPromotion) { | 
 |     // WG14 N2562 only clarified promotions in *printf | 
 |     // For NSLog in ObjC, just preserve -Wformat behavior | 
 |     if (!S.getLangOpts().ObjC && | 
 |         ImplicitMatch != ArgType::NoMatchPromotionTypeConfusion && | 
 |         ImplicitMatch != ArgType::NoMatchTypeConfusion) | 
 |       return true; | 
 |     Match = ArgType::NoMatch; | 
 |   } | 
 |   if (ImplicitMatch == ArgType::NoMatchPedantic || | 
 |       ImplicitMatch == ArgType::NoMatchTypeConfusion) | 
 |     Match = ImplicitMatch; | 
 |   assert(Match != ArgType::MatchPromotion); | 
 |  | 
 |   // Look through unscoped enums to their underlying type. | 
 |   bool IsEnum = false; | 
 |   bool IsScopedEnum = false; | 
 |   QualType IntendedTy = ExprTy; | 
 |   if (const auto *ED = ExprTy->getAsEnumDecl()) { | 
 |     IntendedTy = ED->getIntegerType(); | 
 |     if (!ED->isScoped()) { | 
 |       ExprTy = IntendedTy; | 
 |       // This controls whether we're talking about the underlying type or not, | 
 |       // which we only want to do when it's an unscoped enum. | 
 |       IsEnum = true; | 
 |     } else { | 
 |       IsScopedEnum = true; | 
 |     } | 
 |   } | 
 |  | 
 |   // %C in an Objective-C context prints a unichar, not a wchar_t. | 
 |   // If the argument is an integer of some kind, believe the %C and suggest | 
 |   // a cast instead of changing the conversion specifier. | 
 |   if (isObjCContext() && | 
 |       FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) { | 
 |     if (ExprTy->isIntegralOrUnscopedEnumerationType() && | 
 |         !ExprTy->isCharType()) { | 
 |       // 'unichar' is defined as a typedef of unsigned short, but we should | 
 |       // prefer using the typedef if it is visible. | 
 |       IntendedTy = S.Context.UnsignedShortTy; | 
 |  | 
 |       // While we are here, check if the value is an IntegerLiteral that happens | 
 |       // to be within the valid range. | 
 |       if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E)) { | 
 |         const llvm::APInt &V = IL->getValue(); | 
 |         if (V.getActiveBits() <= S.Context.getTypeSize(IntendedTy)) | 
 |           return true; | 
 |       } | 
 |  | 
 |       LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getBeginLoc(), | 
 |                           Sema::LookupOrdinaryName); | 
 |       if (S.LookupName(Result, S.getCurScope())) { | 
 |         NamedDecl *ND = Result.getFoundDecl(); | 
 |         if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND)) | 
 |           if (TD->getUnderlyingType() == IntendedTy) | 
 |             IntendedTy = | 
 |                 S.Context.getTypedefType(ElaboratedTypeKeyword::None, | 
 |                                          /*Qualifier=*/std::nullopt, TD); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Special-case some of Darwin's platform-independence types by suggesting | 
 |   // casts to primitive types that are known to be large enough. | 
 |   bool ShouldNotPrintDirectly = false; StringRef CastTyName; | 
 |   if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { | 
 |     QualType CastTy; | 
 |     std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); | 
 |     if (!CastTy.isNull()) { | 
 |       // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int | 
 |       // (long in ASTContext). Only complain to pedants or when they're the | 
 |       // underlying type of a scoped enum (which always needs a cast). | 
 |       if (!IsScopedEnum && | 
 |           (CastTyName == "NSInteger" || CastTyName == "NSUInteger") && | 
 |           (AT.isSizeT() || AT.isPtrdiffT()) && | 
 |           AT.matchesType(S.Context, CastTy)) | 
 |         Match = ArgType::NoMatchPedantic; | 
 |       IntendedTy = CastTy; | 
 |       ShouldNotPrintDirectly = true; | 
 |     } | 
 |   } | 
 |  | 
 |   // We may be able to offer a FixItHint if it is a supported type. | 
 |   PrintfSpecifier fixedFS = FS; | 
 |   bool Success = | 
 |       fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); | 
 |  | 
 |   if (Success) { | 
 |     // Get the fix string from the fixed format specifier | 
 |     SmallString<16> buf; | 
 |     llvm::raw_svector_ostream os(buf); | 
 |     fixedFS.toString(os); | 
 |  | 
 |     CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); | 
 |  | 
 |     if (IntendedTy == ExprTy && !ShouldNotPrintDirectly && !IsScopedEnum) { | 
 |       unsigned Diag; | 
 |       switch (Match) { | 
 |       case ArgType::Match: | 
 |       case ArgType::MatchPromotion: | 
 |       case ArgType::NoMatchPromotionTypeConfusion: | 
 |         llvm_unreachable("expected non-matching"); | 
 |       case ArgType::NoMatchSignedness: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch_signedness; | 
 |         break; | 
 |       case ArgType::NoMatchPedantic: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; | 
 |         break; | 
 |       case ArgType::NoMatchTypeConfusion: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; | 
 |         break; | 
 |       case ArgType::NoMatch: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch; | 
 |         break; | 
 |       } | 
 |  | 
 |       // In this case, the specifier is wrong and should be changed to match | 
 |       // the argument. | 
 |       EmitFormatDiagnostic(S.PDiag(Diag) | 
 |                                << AT.getRepresentativeTypeName(S.Context) | 
 |                                << IntendedTy << IsEnum << E->getSourceRange(), | 
 |                            E->getBeginLoc(), | 
 |                            /*IsStringLocation*/ false, SpecRange, | 
 |                            FixItHint::CreateReplacement(SpecRange, os.str())); | 
 |     } else { | 
 |       // The canonical type for formatting this value is different from the | 
 |       // actual type of the expression. (This occurs, for example, with Darwin's | 
 |       // NSInteger on 32-bit platforms, where it is typedef'd as 'int', but | 
 |       // should be printed as 'long' for 64-bit compatibility.) | 
 |       // Rather than emitting a normal format/argument mismatch, we want to | 
 |       // add a cast to the recommended type (and correct the format string | 
 |       // if necessary). We should also do so for scoped enumerations. | 
 |       SmallString<16> CastBuf; | 
 |       llvm::raw_svector_ostream CastFix(CastBuf); | 
 |       CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "("); | 
 |       IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); | 
 |       CastFix << (S.LangOpts.CPlusPlus ? ">" : ")"); | 
 |  | 
 |       SmallVector<FixItHint,4> Hints; | 
 |       ArgType::MatchKind IntendedMatch = AT.matchesType(S.Context, IntendedTy); | 
 |       IntendedMatch = handleFormatSignedness(IntendedMatch, S.getDiagnostics(), | 
 |                                              E->getExprLoc()); | 
 |       if ((IntendedMatch != ArgType::Match) || ShouldNotPrintDirectly) | 
 |         Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); | 
 |  | 
 |       if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { | 
 |         // If there's already a cast present, just replace it. | 
 |         SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc()); | 
 |         Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str())); | 
 |  | 
 |       } else if (!requiresParensToAddCast(E) && !S.LangOpts.CPlusPlus) { | 
 |         // If the expression has high enough precedence, | 
 |         // just write the C-style cast. | 
 |         Hints.push_back( | 
 |             FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str())); | 
 |       } else { | 
 |         // Otherwise, add parens around the expression as well as the cast. | 
 |         CastFix << "("; | 
 |         Hints.push_back( | 
 |             FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str())); | 
 |  | 
 |         // We don't use getLocForEndOfToken because it returns invalid source | 
 |         // locations for macro expansions (by design). | 
 |         SourceLocation EndLoc = S.SourceMgr.getSpellingLoc(E->getEndLoc()); | 
 |         SourceLocation After = EndLoc.getLocWithOffset( | 
 |             Lexer::MeasureTokenLength(EndLoc, S.SourceMgr, S.LangOpts)); | 
 |         Hints.push_back(FixItHint::CreateInsertion(After, ")")); | 
 |       } | 
 |  | 
 |       if (ShouldNotPrintDirectly && !IsScopedEnum) { | 
 |         // The expression has a type that should not be printed directly. | 
 |         // We extract the name from the typedef because we don't want to show | 
 |         // the underlying type in the diagnostic. | 
 |         StringRef Name; | 
 |         if (const auto *TypedefTy = ExprTy->getAs<TypedefType>()) | 
 |           Name = TypedefTy->getDecl()->getName(); | 
 |         else | 
 |           Name = CastTyName; | 
 |         unsigned Diag = Match == ArgType::NoMatchPedantic | 
 |                             ? diag::warn_format_argument_needs_cast_pedantic | 
 |                             : diag::warn_format_argument_needs_cast; | 
 |         EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum | 
 |                                            << E->getSourceRange(), | 
 |                              E->getBeginLoc(), /*IsStringLocation=*/false, | 
 |                              SpecRange, Hints); | 
 |       } else { | 
 |         // In this case, the expression could be printed using a different | 
 |         // specifier, but we've decided that the specifier is probably correct | 
 |         // and we should cast instead. Just use the normal warning message. | 
 |  | 
 |         unsigned Diag = | 
 |             IsScopedEnum | 
 |                 ? diag::warn_format_conversion_argument_type_mismatch_pedantic | 
 |                 : diag::warn_format_conversion_argument_type_mismatch; | 
 |  | 
 |         EmitFormatDiagnostic( | 
 |             S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy | 
 |                           << IsEnum << E->getSourceRange(), | 
 |             E->getBeginLoc(), /*IsStringLocation*/ false, SpecRange, Hints); | 
 |       } | 
 |     } | 
 |   } else { | 
 |     const CharSourceRange &CSR = getSpecifierRange(StartSpecifier, | 
 |                                                    SpecifierLen); | 
 |     // Since the warning for passing non-POD types to variadic functions | 
 |     // was deferred until now, we emit a warning for non-POD | 
 |     // arguments here. | 
 |     bool EmitTypeMismatch = false; | 
 |     switch (S.isValidVarArgType(ExprTy)) { | 
 |     case VarArgKind::Valid: | 
 |     case VarArgKind::ValidInCXX11: { | 
 |       unsigned Diag; | 
 |       switch (Match) { | 
 |       case ArgType::Match: | 
 |       case ArgType::MatchPromotion: | 
 |       case ArgType::NoMatchPromotionTypeConfusion: | 
 |         llvm_unreachable("expected non-matching"); | 
 |       case ArgType::NoMatchSignedness: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch_signedness; | 
 |         break; | 
 |       case ArgType::NoMatchPedantic: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; | 
 |         break; | 
 |       case ArgType::NoMatchTypeConfusion: | 
 |         Diag = diag::warn_format_conversion_argument_type_mismatch_confusion; | 
 |         break; | 
 |       case ArgType::NoMatch: | 
 |         Diag = isInvalidOSLogArgTypeForCodeGen(FSType, ExprTy) | 
 |                    ? diag::err_format_conversion_argument_type_mismatch | 
 |                    : diag::warn_format_conversion_argument_type_mismatch; | 
 |         break; | 
 |       } | 
 |  | 
 |       EmitFormatDiagnostic( | 
 |           S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy | 
 |                         << IsEnum << CSR << E->getSourceRange(), | 
 |           E->getBeginLoc(), /*IsStringLocation*/ false, CSR); | 
 |       break; | 
 |     } | 
 |     case VarArgKind::Undefined: | 
 |     case VarArgKind::MSVCUndefined: | 
 |       if (CallType == VariadicCallType::DoesNotApply) { | 
 |         EmitTypeMismatch = true; | 
 |       } else { | 
 |         EmitFormatDiagnostic( | 
 |             S.PDiag(diag::warn_non_pod_vararg_with_format_string) | 
 |                 << S.getLangOpts().CPlusPlus11 << ExprTy << CallType | 
 |                 << AT.getRepresentativeTypeName(S.Context) << CSR | 
 |                 << E->getSourceRange(), | 
 |             E->getBeginLoc(), /*IsStringLocation*/ false, CSR); | 
 |         checkForCStrMembers(AT, E); | 
 |       } | 
 |       break; | 
 |  | 
 |     case VarArgKind::Invalid: | 
 |       if (CallType == VariadicCallType::DoesNotApply) | 
 |         EmitTypeMismatch = true; | 
 |       else if (ExprTy->isObjCObjectType()) | 
 |         EmitFormatDiagnostic( | 
 |             S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format) | 
 |                 << S.getLangOpts().CPlusPlus11 << ExprTy << CallType | 
 |                 << AT.getRepresentativeTypeName(S.Context) << CSR | 
 |                 << E->getSourceRange(), | 
 |             E->getBeginLoc(), /*IsStringLocation*/ false, CSR); | 
 |       else | 
 |         // FIXME: If this is an initializer list, suggest removing the braces | 
 |         // or inserting a cast to the target type. | 
 |         S.Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg_format) | 
 |             << isa<InitListExpr>(E) << ExprTy << CallType | 
 |             << AT.getRepresentativeTypeName(S.Context) << E->getSourceRange(); | 
 |       break; | 
 |     } | 
 |  | 
 |     if (EmitTypeMismatch) { | 
 |       // The function is not variadic, so we do not generate warnings about | 
 |       // being allowed to pass that object as a variadic argument. Instead, | 
 |       // since there are inherently no printf specifiers for types which cannot | 
 |       // be passed as variadic arguments, emit a plain old specifier mismatch | 
 |       // argument. | 
 |       EmitFormatDiagnostic( | 
 |           S.PDiag(diag::warn_format_conversion_argument_type_mismatch) | 
 |               << AT.getRepresentativeTypeName(S.Context) << ExprTy << false | 
 |               << E->getSourceRange(), | 
 |           E->getBeginLoc(), false, CSR); | 
 |     } | 
 |  | 
 |     assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() && | 
 |            "format string specifier index out of range"); | 
 |     CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | //===--- CHECK: Scanf format string checking ------------------------------===// | 
 |  | 
 | namespace { | 
 |  | 
 | class CheckScanfHandler : public CheckFormatHandler { | 
 | public: | 
 |   CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, | 
 |                     const Expr *origFormatExpr, FormatStringType type, | 
 |                     unsigned firstDataArg, unsigned numDataArgs, | 
 |                     const char *beg, Sema::FormatArgumentPassingKind APK, | 
 |                     ArrayRef<const Expr *> Args, unsigned formatIdx, | 
 |                     bool inFunctionCall, VariadicCallType CallType, | 
 |                     llvm::SmallBitVector &CheckedVarArgs, | 
 |                     UncoveredArgHandler &UncoveredArg) | 
 |       : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, | 
 |                            numDataArgs, beg, APK, Args, formatIdx, | 
 |                            inFunctionCall, CallType, CheckedVarArgs, | 
 |                            UncoveredArg) {} | 
 |  | 
 |   bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, | 
 |                             const char *startSpecifier, | 
 |                             unsigned specifierLen) override; | 
 |  | 
 |   bool HandleInvalidScanfConversionSpecifier( | 
 |           const analyze_scanf::ScanfSpecifier &FS, | 
 |           const char *startSpecifier, | 
 |           unsigned specifierLen) override; | 
 |  | 
 |   void HandleIncompleteScanList(const char *start, const char *end) override; | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | void CheckScanfHandler::HandleIncompleteScanList(const char *start, | 
 |                                                  const char *end) { | 
 |   EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_scanlist_incomplete), | 
 |                        getLocationOfByte(end), /*IsStringLocation*/true, | 
 |                        getSpecifierRange(start, end - start)); | 
 | } | 
 |  | 
 | bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( | 
 |                                         const analyze_scanf::ScanfSpecifier &FS, | 
 |                                         const char *startSpecifier, | 
 |                                         unsigned specifierLen) { | 
 |   const analyze_scanf::ScanfConversionSpecifier &CS = | 
 |     FS.getConversionSpecifier(); | 
 |  | 
 |   return HandleInvalidConversionSpecifier(FS.getArgIndex(), | 
 |                                           getLocationOfByte(CS.getStart()), | 
 |                                           startSpecifier, specifierLen, | 
 |                                           CS.getStart(), CS.getLength()); | 
 | } | 
 |  | 
 | bool CheckScanfHandler::HandleScanfSpecifier( | 
 |                                        const analyze_scanf::ScanfSpecifier &FS, | 
 |                                        const char *startSpecifier, | 
 |                                        unsigned specifierLen) { | 
 |   using namespace analyze_scanf; | 
 |   using namespace analyze_format_string; | 
 |  | 
 |   const ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); | 
 |  | 
 |   // Handle case where '%' and '*' don't consume an argument.  These shouldn't | 
 |   // be used to decide if we are using positional arguments consistently. | 
 |   if (FS.consumesDataArgument()) { | 
 |     if (atFirstArg) { | 
 |       atFirstArg = false; | 
 |       usesPositionalArgs = FS.usesPositionalArg(); | 
 |     } | 
 |     else if (usesPositionalArgs != FS.usesPositionalArg()) { | 
 |       HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()), | 
 |                                         startSpecifier, specifierLen); | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |   // Check if the field with is non-zero. | 
 |   const OptionalAmount &Amt = FS.getFieldWidth(); | 
 |   if (Amt.getHowSpecified() == OptionalAmount::Constant) { | 
 |     if (Amt.getConstantAmount() == 0) { | 
 |       const CharSourceRange &R = getSpecifierRange(Amt.getStart(), | 
 |                                                    Amt.getConstantLength()); | 
 |       EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_nonzero_width), | 
 |                            getLocationOfByte(Amt.getStart()), | 
 |                            /*IsStringLocation*/true, R, | 
 |                            FixItHint::CreateRemoval(R)); | 
 |     } | 
 |   } | 
 |  | 
 |   if (!FS.consumesDataArgument()) { | 
 |     // FIXME: Technically specifying a precision or field width here | 
 |     // makes no sense.  Worth issuing a warning at some point. | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Consume the argument. | 
 |   unsigned argIndex = FS.getArgIndex(); | 
 |   if (argIndex < NumDataArgs) { | 
 |       // The check to see if the argIndex is valid will come later. | 
 |       // We set the bit here because we may exit early from this | 
 |       // function if we encounter some other error. | 
 |     CoveredArgs.set(argIndex); | 
 |   } | 
 |  | 
 |   // Check the length modifier is valid with the given conversion specifier. | 
 |   if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(), | 
 |                                  S.getLangOpts())) | 
 |     HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, | 
 |                                 diag::warn_format_nonsensical_length); | 
 |   else if (!FS.hasStandardLengthModifier()) | 
 |     HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); | 
 |   else if (!FS.hasStandardLengthConversionCombination()) | 
 |     HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, | 
 |                                 diag::warn_format_non_standard_conversion_spec); | 
 |  | 
 |   if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) | 
 |     HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); | 
 |  | 
 |   // The remaining checks depend on the data arguments. | 
 |   if (!HasFormatArguments()) | 
 |     return true; | 
 |  | 
 |   if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) | 
 |     return false; | 
 |  | 
 |   // Check that the argument type matches the format specifier. | 
 |   const Expr *Ex = getDataArg(argIndex); | 
 |   if (!Ex) | 
 |     return true; | 
 |  | 
 |   const analyze_format_string::ArgType &AT = FS.getArgType(S.Context); | 
 |  | 
 |   if (!AT.isValid()) { | 
 |     return true; | 
 |   } | 
 |  | 
 |   analyze_format_string::ArgType::MatchKind Match = | 
 |       AT.matchesType(S.Context, Ex->getType()); | 
 |   Match = handleFormatSignedness(Match, S.getDiagnostics(), Ex->getExprLoc()); | 
 |   if (Match == analyze_format_string::ArgType::Match) | 
 |     return true; | 
 |   bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic; | 
 |   bool Signedness = Match == analyze_format_string::ArgType::NoMatchSignedness; | 
 |  | 
 |   ScanfSpecifier fixedFS = FS; | 
 |   bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), | 
 |                                  S.getLangOpts(), S.Context); | 
 |  | 
 |   unsigned Diag = | 
 |       Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic | 
 |       : Signedness | 
 |           ? diag::warn_format_conversion_argument_type_mismatch_signedness | 
 |           : diag::warn_format_conversion_argument_type_mismatch; | 
 |  | 
 |   if (Success) { | 
 |     // Get the fix string from the fixed format specifier. | 
 |     SmallString<128> buf; | 
 |     llvm::raw_svector_ostream os(buf); | 
 |     fixedFS.toString(os); | 
 |  | 
 |     EmitFormatDiagnostic( | 
 |         S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) | 
 |                       << Ex->getType() << false << Ex->getSourceRange(), | 
 |         Ex->getBeginLoc(), | 
 |         /*IsStringLocation*/ false, | 
 |         getSpecifierRange(startSpecifier, specifierLen), | 
 |         FixItHint::CreateReplacement( | 
 |             getSpecifierRange(startSpecifier, specifierLen), os.str())); | 
 |   } else { | 
 |     EmitFormatDiagnostic(S.PDiag(Diag) | 
 |                              << AT.getRepresentativeTypeName(S.Context) | 
 |                              << Ex->getType() << false << Ex->getSourceRange(), | 
 |                          Ex->getBeginLoc(), | 
 |                          /*IsStringLocation*/ false, | 
 |                          getSpecifierRange(startSpecifier, specifierLen)); | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | static bool CompareFormatSpecifiers(Sema &S, const StringLiteral *Ref, | 
 |                                     ArrayRef<EquatableFormatArgument> RefArgs, | 
 |                                     const StringLiteral *Fmt, | 
 |                                     ArrayRef<EquatableFormatArgument> FmtArgs, | 
 |                                     const Expr *FmtExpr, bool InFunctionCall) { | 
 |   bool HadError = false; | 
 |   auto FmtIter = FmtArgs.begin(), FmtEnd = FmtArgs.end(); | 
 |   auto RefIter = RefArgs.begin(), RefEnd = RefArgs.end(); | 
 |   while (FmtIter < FmtEnd && RefIter < RefEnd) { | 
 |     // In positional-style format strings, the same specifier can appear | 
 |     // multiple times (like %2$i %2$d). Specifiers in both RefArgs and FmtArgs | 
 |     // are sorted by getPosition(), and we process each range of equal | 
 |     // getPosition() values as one group. | 
 |     // RefArgs are taken from a string literal that was given to | 
 |     // attribute(format_matches), and if we got this far, we have already | 
 |     // verified that if it has positional specifiers that appear in multiple | 
 |     // locations, then they are all mutually compatible. What's left for us to | 
 |     // do is verify that all specifiers with the same position in FmtArgs are | 
 |     // compatible with the RefArgs specifiers. We check each specifier from | 
 |     // FmtArgs against the first member of the RefArgs group. | 
 |     for (; FmtIter < FmtEnd; ++FmtIter) { | 
 |       // Clang does not diagnose missing format specifiers in positional-style | 
 |       // strings (TODO: which it probably should do, as it is UB to skip over a | 
 |       // format argument). Skip specifiers if needed. | 
 |       if (FmtIter->getPosition() < RefIter->getPosition()) | 
 |         continue; | 
 |  | 
 |       // Delimits a new getPosition() value. | 
 |       if (FmtIter->getPosition() > RefIter->getPosition()) | 
 |         break; | 
 |  | 
 |       HadError |= | 
 |           !FmtIter->VerifyCompatible(S, *RefIter, FmtExpr, InFunctionCall); | 
 |     } | 
 |  | 
 |     // Jump RefIter to the start of the next group. | 
 |     RefIter = std::find_if(RefIter + 1, RefEnd, [=](const auto &Arg) { | 
 |       return Arg.getPosition() != RefIter->getPosition(); | 
 |     }); | 
 |   } | 
 |  | 
 |   if (FmtIter < FmtEnd) { | 
 |     CheckFormatHandler::EmitFormatDiagnostic( | 
 |         S, InFunctionCall, FmtExpr, | 
 |         S.PDiag(diag::warn_format_cmp_specifier_arity) << 1, | 
 |         FmtExpr->getBeginLoc(), false, FmtIter->getSourceRange()); | 
 |     HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with) << 1; | 
 |   } else if (RefIter < RefEnd) { | 
 |     CheckFormatHandler::EmitFormatDiagnostic( | 
 |         S, InFunctionCall, FmtExpr, | 
 |         S.PDiag(diag::warn_format_cmp_specifier_arity) << 0, | 
 |         FmtExpr->getBeginLoc(), false, Fmt->getSourceRange()); | 
 |     HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with) | 
 |                << 1 << RefIter->getSourceRange(); | 
 |   } | 
 |   return !HadError; | 
 | } | 
 |  | 
 | static void CheckFormatString( | 
 |     Sema &S, const FormatStringLiteral *FExpr, | 
 |     const StringLiteral *ReferenceFormatString, const Expr *OrigFormatExpr, | 
 |     ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK, | 
 |     unsigned format_idx, unsigned firstDataArg, FormatStringType Type, | 
 |     bool inFunctionCall, VariadicCallType CallType, | 
 |     llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, | 
 |     bool IgnoreStringsWithoutSpecifiers) { | 
 |   // CHECK: is the format string a wide literal? | 
 |   if (!FExpr->isAscii() && !FExpr->isUTF8()) { | 
 |     CheckFormatHandler::EmitFormatDiagnostic( | 
 |         S, inFunctionCall, Args[format_idx], | 
 |         S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getBeginLoc(), | 
 |         /*IsStringLocation*/ true, OrigFormatExpr->getSourceRange()); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Str - The format string.  NOTE: this is NOT null-terminated! | 
 |   StringRef StrRef = FExpr->getString(); | 
 |   const char *Str = StrRef.data(); | 
 |   // Account for cases where the string literal is truncated in a declaration. | 
 |   const ConstantArrayType *T = | 
 |     S.Context.getAsConstantArrayType(FExpr->getType()); | 
 |   assert(T && "String literal not of constant array type!"); | 
 |   size_t TypeSize = T->getZExtSize(); | 
 |   size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); | 
 |   const unsigned numDataArgs = Args.size() - firstDataArg; | 
 |  | 
 |   if (IgnoreStringsWithoutSpecifiers && | 
 |       !analyze_format_string::parseFormatStringHasFormattingSpecifiers( | 
 |           Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo())) | 
 |     return; | 
 |  | 
 |   // Emit a warning if the string literal is truncated and does not contain an | 
 |   // embedded null character. | 
 |   if (TypeSize <= StrRef.size() && !StrRef.substr(0, TypeSize).contains('\0')) { | 
 |     CheckFormatHandler::EmitFormatDiagnostic( | 
 |         S, inFunctionCall, Args[format_idx], | 
 |         S.PDiag(diag::warn_printf_format_string_not_null_terminated), | 
 |         FExpr->getBeginLoc(), | 
 |         /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange()); | 
 |     return; | 
 |   } | 
 |  | 
 |   // CHECK: empty format string? | 
 |   if (StrLen == 0 && numDataArgs > 0) { | 
 |     CheckFormatHandler::EmitFormatDiagnostic( | 
 |         S, inFunctionCall, Args[format_idx], | 
 |         S.PDiag(diag::warn_empty_format_string), FExpr->getBeginLoc(), | 
 |         /*IsStringLocation*/ true, OrigFormatExpr->getSourceRange()); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (Type == FormatStringType::Printf || Type == FormatStringType::NSString || | 
 |       Type == FormatStringType::Kprintf || | 
 |       Type == FormatStringType::FreeBSDKPrintf || | 
 |       Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace) { | 
 |     bool IsObjC = | 
 |         Type == FormatStringType::NSString || Type == FormatStringType::OSTrace; | 
 |     if (ReferenceFormatString == nullptr) { | 
 |       CheckPrintfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, | 
 |                            numDataArgs, IsObjC, Str, APK, Args, format_idx, | 
 |                            inFunctionCall, CallType, CheckedVarArgs, | 
 |                            UncoveredArg); | 
 |  | 
 |       if (!analyze_format_string::ParsePrintfString( | 
 |               H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(), | 
 |               Type == FormatStringType::Kprintf || | 
 |                   Type == FormatStringType::FreeBSDKPrintf)) | 
 |         H.DoneProcessing(); | 
 |     } else { | 
 |       S.CheckFormatStringsCompatible( | 
 |           Type, ReferenceFormatString, FExpr->getFormatString(), | 
 |           inFunctionCall ? nullptr : Args[format_idx]); | 
 |     } | 
 |   } else if (Type == FormatStringType::Scanf) { | 
 |     CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, | 
 |                         numDataArgs, Str, APK, Args, format_idx, inFunctionCall, | 
 |                         CallType, CheckedVarArgs, UncoveredArg); | 
 |  | 
 |     if (!analyze_format_string::ParseScanfString( | 
 |             H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo())) | 
 |       H.DoneProcessing(); | 
 |   } // TODO: handle other formats | 
 | } | 
 |  | 
 | bool Sema::CheckFormatStringsCompatible( | 
 |     FormatStringType Type, const StringLiteral *AuthoritativeFormatString, | 
 |     const StringLiteral *TestedFormatString, const Expr *FunctionCallArg) { | 
 |   if (Type != FormatStringType::Printf && Type != FormatStringType::NSString && | 
 |       Type != FormatStringType::Kprintf && | 
 |       Type != FormatStringType::FreeBSDKPrintf && | 
 |       Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace) | 
 |     return true; | 
 |  | 
 |   bool IsObjC = | 
 |       Type == FormatStringType::NSString || Type == FormatStringType::OSTrace; | 
 |   llvm::SmallVector<EquatableFormatArgument, 9> RefArgs, FmtArgs; | 
 |   FormatStringLiteral RefLit = AuthoritativeFormatString; | 
 |   FormatStringLiteral TestLit = TestedFormatString; | 
 |   const Expr *Arg; | 
 |   bool DiagAtStringLiteral; | 
 |   if (FunctionCallArg) { | 
 |     Arg = FunctionCallArg; | 
 |     DiagAtStringLiteral = false; | 
 |   } else { | 
 |     Arg = TestedFormatString; | 
 |     DiagAtStringLiteral = true; | 
 |   } | 
 |   if (DecomposePrintfHandler::GetSpecifiers(*this, &RefLit, | 
 |                                             AuthoritativeFormatString, Type, | 
 |                                             IsObjC, true, RefArgs) && | 
 |       DecomposePrintfHandler::GetSpecifiers(*this, &TestLit, Arg, Type, IsObjC, | 
 |                                             DiagAtStringLiteral, FmtArgs)) { | 
 |     return CompareFormatSpecifiers(*this, AuthoritativeFormatString, RefArgs, | 
 |                                    TestedFormatString, FmtArgs, Arg, | 
 |                                    DiagAtStringLiteral); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::ValidateFormatString(FormatStringType Type, | 
 |                                 const StringLiteral *Str) { | 
 |   if (Type != FormatStringType::Printf && Type != FormatStringType::NSString && | 
 |       Type != FormatStringType::Kprintf && | 
 |       Type != FormatStringType::FreeBSDKPrintf && | 
 |       Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace) | 
 |     return true; | 
 |  | 
 |   FormatStringLiteral RefLit = Str; | 
 |   llvm::SmallVector<EquatableFormatArgument, 9> Args; | 
 |   bool IsObjC = | 
 |       Type == FormatStringType::NSString || Type == FormatStringType::OSTrace; | 
 |   if (!DecomposePrintfHandler::GetSpecifiers(*this, &RefLit, Str, Type, IsObjC, | 
 |                                              true, Args)) | 
 |     return false; | 
 |  | 
 |   // Group arguments by getPosition() value, and check that each member of the | 
 |   // group is compatible with the first member. This verifies that when | 
 |   // positional arguments are used multiple times (such as %2$i %2$d), all uses | 
 |   // are mutually compatible. As an optimization, don't test the first member | 
 |   // against itself. | 
 |   bool HadError = false; | 
 |   auto Iter = Args.begin(); | 
 |   auto End = Args.end(); | 
 |   while (Iter != End) { | 
 |     const auto &FirstInGroup = *Iter; | 
 |     for (++Iter; | 
 |          Iter != End && Iter->getPosition() == FirstInGroup.getPosition(); | 
 |          ++Iter) { | 
 |       HadError |= !Iter->VerifyCompatible(*this, FirstInGroup, Str, true); | 
 |     } | 
 |   } | 
 |   return !HadError; | 
 | } | 
 |  | 
 | bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) { | 
 |   // Str - The format string.  NOTE: this is NOT null-terminated! | 
 |   StringRef StrRef = FExpr->getString(); | 
 |   const char *Str = StrRef.data(); | 
 |   // Account for cases where the string literal is truncated in a declaration. | 
 |   const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); | 
 |   assert(T && "String literal not of constant array type!"); | 
 |   size_t TypeSize = T->getZExtSize(); | 
 |   size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); | 
 |   return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen, | 
 |                                                          getLangOpts(), | 
 |                                                          Context.getTargetInfo()); | 
 | } | 
 |  | 
 | //===--- CHECK: Warn on use of wrong absolute value function. -------------===// | 
 |  | 
 | // Returns the related absolute value function that is larger, of 0 if one | 
 | // does not exist. | 
 | static unsigned getLargerAbsoluteValueFunction(unsigned AbsFunction) { | 
 |   switch (AbsFunction) { | 
 |   default: | 
 |     return 0; | 
 |  | 
 |   case Builtin::BI__builtin_abs: | 
 |     return Builtin::BI__builtin_labs; | 
 |   case Builtin::BI__builtin_labs: | 
 |     return Builtin::BI__builtin_llabs; | 
 |   case Builtin::BI__builtin_llabs: | 
 |     return 0; | 
 |  | 
 |   case Builtin::BI__builtin_fabsf: | 
 |     return Builtin::BI__builtin_fabs; | 
 |   case Builtin::BI__builtin_fabs: | 
 |     return Builtin::BI__builtin_fabsl; | 
 |   case Builtin::BI__builtin_fabsl: | 
 |     return 0; | 
 |  | 
 |   case Builtin::BI__builtin_cabsf: | 
 |     return Builtin::BI__builtin_cabs; | 
 |   case Builtin::BI__builtin_cabs: | 
 |     return Builtin::BI__builtin_cabsl; | 
 |   case Builtin::BI__builtin_cabsl: | 
 |     return 0; | 
 |  | 
 |   case Builtin::BIabs: | 
 |     return Builtin::BIlabs; | 
 |   case Builtin::BIlabs: | 
 |     return Builtin::BIllabs; | 
 |   case Builtin::BIllabs: | 
 |     return 0; | 
 |  | 
 |   case Builtin::BIfabsf: | 
 |     return Builtin::BIfabs; | 
 |   case Builtin::BIfabs: | 
 |     return Builtin::BIfabsl; | 
 |   case Builtin::BIfabsl: | 
 |     return 0; | 
 |  | 
 |   case Builtin::BIcabsf: | 
 |    return Builtin::BIcabs; | 
 |   case Builtin::BIcabs: | 
 |     return Builtin::BIcabsl; | 
 |   case Builtin::BIcabsl: | 
 |     return 0; | 
 |   } | 
 | } | 
 |  | 
 | // Returns the argument type of the absolute value function. | 
 | static QualType getAbsoluteValueArgumentType(ASTContext &Context, | 
 |                                              unsigned AbsType) { | 
 |   if (AbsType == 0) | 
 |     return QualType(); | 
 |  | 
 |   ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None; | 
 |   QualType BuiltinType = Context.GetBuiltinType(AbsType, Error); | 
 |   if (Error != ASTContext::GE_None) | 
 |     return QualType(); | 
 |  | 
 |   const FunctionProtoType *FT = BuiltinType->getAs<FunctionProtoType>(); | 
 |   if (!FT) | 
 |     return QualType(); | 
 |  | 
 |   if (FT->getNumParams() != 1) | 
 |     return QualType(); | 
 |  | 
 |   return FT->getParamType(0); | 
 | } | 
 |  | 
 | // Returns the best absolute value function, or zero, based on type and | 
 | // current absolute value function. | 
 | static unsigned getBestAbsFunction(ASTContext &Context, QualType ArgType, | 
 |                                    unsigned AbsFunctionKind) { | 
 |   unsigned BestKind = 0; | 
 |   uint64_t ArgSize = Context.getTypeSize(ArgType); | 
 |   for (unsigned Kind = AbsFunctionKind; Kind != 0; | 
 |        Kind = getLargerAbsoluteValueFunction(Kind)) { | 
 |     QualType ParamType = getAbsoluteValueArgumentType(Context, Kind); | 
 |     if (Context.getTypeSize(ParamType) >= ArgSize) { | 
 |       if (BestKind == 0) | 
 |         BestKind = Kind; | 
 |       else if (Context.hasSameType(ParamType, ArgType)) { | 
 |         BestKind = Kind; | 
 |         break; | 
 |       } | 
 |     } | 
 |   } | 
 |   return BestKind; | 
 | } | 
 |  | 
 | enum AbsoluteValueKind { | 
 |   AVK_Integer, | 
 |   AVK_Floating, | 
 |   AVK_Complex | 
 | }; | 
 |  | 
 | static AbsoluteValueKind getAbsoluteValueKind(QualType T) { | 
 |   if (T->isIntegralOrEnumerationType()) | 
 |     return AVK_Integer; | 
 |   if (T->isRealFloatingType()) | 
 |     return AVK_Floating; | 
 |   if (T->isAnyComplexType()) | 
 |     return AVK_Complex; | 
 |  | 
 |   llvm_unreachable("Type not integer, floating, or complex"); | 
 | } | 
 |  | 
 | // Changes the absolute value function to a different type.  Preserves whether | 
 | // the function is a builtin. | 
 | static unsigned changeAbsFunction(unsigned AbsKind, | 
 |                                   AbsoluteValueKind ValueKind) { | 
 |   switch (ValueKind) { | 
 |   case AVK_Integer: | 
 |     switch (AbsKind) { | 
 |     default: | 
 |       return 0; | 
 |     case Builtin::BI__builtin_fabsf: | 
 |     case Builtin::BI__builtin_fabs: | 
 |     case Builtin::BI__builtin_fabsl: | 
 |     case Builtin::BI__builtin_cabsf: | 
 |     case Builtin::BI__builtin_cabs: | 
 |     case Builtin::BI__builtin_cabsl: | 
 |       return Builtin::BI__builtin_abs; | 
 |     case Builtin::BIfabsf: | 
 |     case Builtin::BIfabs: | 
 |     case Builtin::BIfabsl: | 
 |     case Builtin::BIcabsf: | 
 |     case Builtin::BIcabs: | 
 |     case Builtin::BIcabsl: | 
 |       return Builtin::BIabs; | 
 |     } | 
 |   case AVK_Floating: | 
 |     switch (AbsKind) { | 
 |     default: | 
 |       return 0; | 
 |     case Builtin::BI__builtin_abs: | 
 |     case Builtin::BI__builtin_labs: | 
 |     case Builtin::BI__builtin_llabs: | 
 |     case Builtin::BI__builtin_cabsf: | 
 |     case Builtin::BI__builtin_cabs: | 
 |     case Builtin::BI__builtin_cabsl: | 
 |       return Builtin::BI__builtin_fabsf; | 
 |     case Builtin::BIabs: | 
 |     case Builtin::BIlabs: | 
 |     case Builtin::BIllabs: | 
 |     case Builtin::BIcabsf: | 
 |     case Builtin::BIcabs: | 
 |     case Builtin::BIcabsl: | 
 |       return Builtin::BIfabsf; | 
 |     } | 
 |   case AVK_Complex: | 
 |     switch (AbsKind) { | 
 |     default: | 
 |       return 0; | 
 |     case Builtin::BI__builtin_abs: | 
 |     case Builtin::BI__builtin_labs: | 
 |     case Builtin::BI__builtin_llabs: | 
 |     case Builtin::BI__builtin_fabsf: | 
 |     case Builtin::BI__builtin_fabs: | 
 |     case Builtin::BI__builtin_fabsl: | 
 |       return Builtin::BI__builtin_cabsf; | 
 |     case Builtin::BIabs: | 
 |     case Builtin::BIlabs: | 
 |     case Builtin::BIllabs: | 
 |     case Builtin::BIfabsf: | 
 |     case Builtin::BIfabs: | 
 |     case Builtin::BIfabsl: | 
 |       return Builtin::BIcabsf; | 
 |     } | 
 |   } | 
 |   llvm_unreachable("Unable to convert function"); | 
 | } | 
 |  | 
 | static unsigned getAbsoluteValueFunctionKind(const FunctionDecl *FDecl) { | 
 |   const IdentifierInfo *FnInfo = FDecl->getIdentifier(); | 
 |   if (!FnInfo) | 
 |     return 0; | 
 |  | 
 |   switch (FDecl->getBuiltinID()) { | 
 |   default: | 
 |     return 0; | 
 |   case Builtin::BI__builtin_abs: | 
 |   case Builtin::BI__builtin_fabs: | 
 |   case Builtin::BI__builtin_fabsf: | 
 |   case Builtin::BI__builtin_fabsl: | 
 |   case Builtin::BI__builtin_labs: | 
 |   case Builtin::BI__builtin_llabs: | 
 |   case Builtin::BI__builtin_cabs: | 
 |   case Builtin::BI__builtin_cabsf: | 
 |   case Builtin::BI__builtin_cabsl: | 
 |   case Builtin::BIabs: | 
 |   case Builtin::BIlabs: | 
 |   case Builtin::BIllabs: | 
 |   case Builtin::BIfabs: | 
 |   case Builtin::BIfabsf: | 
 |   case Builtin::BIfabsl: | 
 |   case Builtin::BIcabs: | 
 |   case Builtin::BIcabsf: | 
 |   case Builtin::BIcabsl: | 
 |     return FDecl->getBuiltinID(); | 
 |   } | 
 |   llvm_unreachable("Unknown Builtin type"); | 
 | } | 
 |  | 
 | // If the replacement is valid, emit a note with replacement function. | 
 | // Additionally, suggest including the proper header if not already included. | 
 | static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range, | 
 |                             unsigned AbsKind, QualType ArgType) { | 
 |   bool EmitHeaderHint = true; | 
 |   const char *HeaderName = nullptr; | 
 |   std::string FunctionName; | 
 |   if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) { | 
 |     FunctionName = "std::abs"; | 
 |     if (ArgType->isIntegralOrEnumerationType()) { | 
 |       HeaderName = "cstdlib"; | 
 |     } else if (ArgType->isRealFloatingType()) { | 
 |       HeaderName = "cmath"; | 
 |     } else { | 
 |       llvm_unreachable("Invalid Type"); | 
 |     } | 
 |  | 
 |     // Lookup all std::abs | 
 |     if (NamespaceDecl *Std = S.getStdNamespace()) { | 
 |       LookupResult R(S, &S.Context.Idents.get("abs"), Loc, Sema::LookupAnyName); | 
 |       R.suppressDiagnostics(); | 
 |       S.LookupQualifiedName(R, Std); | 
 |  | 
 |       for (const auto *I : R) { | 
 |         const FunctionDecl *FDecl = nullptr; | 
 |         if (const UsingShadowDecl *UsingD = dyn_cast<UsingShadowDecl>(I)) { | 
 |           FDecl = dyn_cast<FunctionDecl>(UsingD->getTargetDecl()); | 
 |         } else { | 
 |           FDecl = dyn_cast<FunctionDecl>(I); | 
 |         } | 
 |         if (!FDecl) | 
 |           continue; | 
 |  | 
 |         // Found std::abs(), check that they are the right ones. | 
 |         if (FDecl->getNumParams() != 1) | 
 |           continue; | 
 |  | 
 |         // Check that the parameter type can handle the argument. | 
 |         QualType ParamType = FDecl->getParamDecl(0)->getType(); | 
 |         if (getAbsoluteValueKind(ArgType) == getAbsoluteValueKind(ParamType) && | 
 |             S.Context.getTypeSize(ArgType) <= | 
 |                 S.Context.getTypeSize(ParamType)) { | 
 |           // Found a function, don't need the header hint. | 
 |           EmitHeaderHint = false; | 
 |           break; | 
 |         } | 
 |       } | 
 |     } | 
 |   } else { | 
 |     FunctionName = S.Context.BuiltinInfo.getName(AbsKind); | 
 |     HeaderName = S.Context.BuiltinInfo.getHeaderName(AbsKind); | 
 |  | 
 |     if (HeaderName) { | 
 |       DeclarationName DN(&S.Context.Idents.get(FunctionName)); | 
 |       LookupResult R(S, DN, Loc, Sema::LookupAnyName); | 
 |       R.suppressDiagnostics(); | 
 |       S.LookupName(R, S.getCurScope()); | 
 |  | 
 |       if (R.isSingleResult()) { | 
 |         FunctionDecl *FD = dyn_cast<FunctionDecl>(R.getFoundDecl()); | 
 |         if (FD && FD->getBuiltinID() == AbsKind) { | 
 |           EmitHeaderHint = false; | 
 |         } else { | 
 |           return; | 
 |         } | 
 |       } else if (!R.empty()) { | 
 |         return; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   S.Diag(Loc, diag::note_replace_abs_function) | 
 |       << FunctionName << FixItHint::CreateReplacement(Range, FunctionName); | 
 |  | 
 |   if (!HeaderName) | 
 |     return; | 
 |  | 
 |   if (!EmitHeaderHint) | 
 |     return; | 
 |  | 
 |   S.Diag(Loc, diag::note_include_header_or_declare) << HeaderName | 
 |                                                     << FunctionName; | 
 | } | 
 |  | 
 | template <std::size_t StrLen> | 
 | static bool IsStdFunction(const FunctionDecl *FDecl, | 
 |                           const char (&Str)[StrLen]) { | 
 |   if (!FDecl) | 
 |     return false; | 
 |   if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr(Str)) | 
 |     return false; | 
 |   if (!FDecl->isInStdNamespace()) | 
 |     return false; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | enum class MathCheck { NaN, Inf }; | 
 | static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) { | 
 |   auto MatchesAny = [&](std::initializer_list<llvm::StringRef> names) { | 
 |     return llvm::is_contained(names, calleeName); | 
 |   }; | 
 |  | 
 |   switch (Check) { | 
 |   case MathCheck::NaN: | 
 |     return MatchesAny({"__builtin_nan", "__builtin_nanf", "__builtin_nanl", | 
 |                        "__builtin_nanf16", "__builtin_nanf128"}); | 
 |   case MathCheck::Inf: | 
 |     return MatchesAny({"__builtin_inf", "__builtin_inff", "__builtin_infl", | 
 |                        "__builtin_inff16", "__builtin_inff128"}); | 
 |   } | 
 |   llvm_unreachable("unknown MathCheck"); | 
 | } | 
 |  | 
 | static bool IsInfinityFunction(const FunctionDecl *FDecl) { | 
 |   if (FDecl->getName() != "infinity") | 
 |     return false; | 
 |  | 
 |   if (const CXXMethodDecl *MDecl = dyn_cast<CXXMethodDecl>(FDecl)) { | 
 |     const CXXRecordDecl *RDecl = MDecl->getParent(); | 
 |     if (RDecl->getName() != "numeric_limits") | 
 |       return false; | 
 |  | 
 |     if (const NamespaceDecl *NSDecl = | 
 |             dyn_cast<NamespaceDecl>(RDecl->getDeclContext())) | 
 |       return NSDecl->isStdNamespace(); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | void Sema::CheckInfNaNFunction(const CallExpr *Call, | 
 |                                const FunctionDecl *FDecl) { | 
 |   if (!FDecl->getIdentifier()) | 
 |     return; | 
 |  | 
 |   FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts()); | 
 |   if (FPO.getNoHonorNaNs() && | 
 |       (IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") || | 
 |        IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN))) { | 
 |     Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | 
 |         << 1 << 0 << Call->getSourceRange(); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (FPO.getNoHonorInfs() && | 
 |       (IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite") || | 
 |        IsInfinityFunction(FDecl) || | 
 |        IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf))) { | 
 |     Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | 
 |         << 0 << 0 << Call->getSourceRange(); | 
 |   } | 
 | } | 
 |  | 
 | void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, | 
 |                                       const FunctionDecl *FDecl) { | 
 |   if (Call->getNumArgs() != 1) | 
 |     return; | 
 |  | 
 |   unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl); | 
 |   bool IsStdAbs = IsStdFunction(FDecl, "abs"); | 
 |   if (AbsKind == 0 && !IsStdAbs) | 
 |     return; | 
 |  | 
 |   QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType(); | 
 |   QualType ParamType = Call->getArg(0)->getType(); | 
 |  | 
 |   // Unsigned types cannot be negative.  Suggest removing the absolute value | 
 |   // function call. | 
 |   if (ArgType->isUnsignedIntegerType()) { | 
 |     std::string FunctionName = | 
 |         IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind); | 
 |     Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType; | 
 |     Diag(Call->getExprLoc(), diag::note_remove_abs) | 
 |         << FunctionName | 
 |         << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Taking the absolute value of a pointer is very suspicious, they probably | 
 |   // wanted to index into an array, dereference a pointer, call a function, etc. | 
 |   if (ArgType->isPointerType() || ArgType->canDecayToPointerType()) { | 
 |     unsigned DiagType = 0; | 
 |     if (ArgType->isFunctionType()) | 
 |       DiagType = 1; | 
 |     else if (ArgType->isArrayType()) | 
 |       DiagType = 2; | 
 |  | 
 |     Diag(Call->getExprLoc(), diag::warn_pointer_abs) << DiagType << ArgType; | 
 |     return; | 
 |   } | 
 |  | 
 |   // std::abs has overloads which prevent most of the absolute value problems | 
 |   // from occurring. | 
 |   if (IsStdAbs) | 
 |     return; | 
 |  | 
 |   AbsoluteValueKind ArgValueKind = getAbsoluteValueKind(ArgType); | 
 |   AbsoluteValueKind ParamValueKind = getAbsoluteValueKind(ParamType); | 
 |  | 
 |   // The argument and parameter are the same kind.  Check if they are the right | 
 |   // size. | 
 |   if (ArgValueKind == ParamValueKind) { | 
 |     if (Context.getTypeSize(ArgType) <= Context.getTypeSize(ParamType)) | 
 |       return; | 
 |  | 
 |     unsigned NewAbsKind = getBestAbsFunction(Context, ArgType, AbsKind); | 
 |     Diag(Call->getExprLoc(), diag::warn_abs_too_small) | 
 |         << FDecl << ArgType << ParamType; | 
 |  | 
 |     if (NewAbsKind == 0) | 
 |       return; | 
 |  | 
 |     emitReplacement(*this, Call->getExprLoc(), | 
 |                     Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); | 
 |     return; | 
 |   } | 
 |  | 
 |   // ArgValueKind != ParamValueKind | 
 |   // The wrong type of absolute value function was used.  Attempt to find the | 
 |   // proper one. | 
 |   unsigned NewAbsKind = changeAbsFunction(AbsKind, ArgValueKind); | 
 |   NewAbsKind = getBestAbsFunction(Context, ArgType, NewAbsKind); | 
 |   if (NewAbsKind == 0) | 
 |     return; | 
 |  | 
 |   Diag(Call->getExprLoc(), diag::warn_wrong_absolute_value_type) | 
 |       << FDecl << ParamValueKind << ArgValueKind; | 
 |  | 
 |   emitReplacement(*this, Call->getExprLoc(), | 
 |                   Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); | 
 | } | 
 |  | 
 | //===--- CHECK: Warn on use of std::max and unsigned zero. r---------------===// | 
 | void Sema::CheckMaxUnsignedZero(const CallExpr *Call, | 
 |                                 const FunctionDecl *FDecl) { | 
 |   if (!Call || !FDecl) return; | 
 |  | 
 |   // Ignore template specializations and macros. | 
 |   if (inTemplateInstantiation()) return; | 
 |   if (Call->getExprLoc().isMacroID()) return; | 
 |  | 
 |   // Only care about the one template argument, two function parameter std::max | 
 |   if (Call->getNumArgs() != 2) return; | 
 |   if (!IsStdFunction(FDecl, "max")) return; | 
 |   const auto * ArgList = FDecl->getTemplateSpecializationArgs(); | 
 |   if (!ArgList) return; | 
 |   if (ArgList->size() != 1) return; | 
 |  | 
 |   // Check that template type argument is unsigned integer. | 
 |   const auto& TA = ArgList->get(0); | 
 |   if (TA.getKind() != TemplateArgument::Type) return; | 
 |   QualType ArgType = TA.getAsType(); | 
 |   if (!ArgType->isUnsignedIntegerType()) return; | 
 |  | 
 |   // See if either argument is a literal zero. | 
 |   auto IsLiteralZeroArg = [](const Expr* E) -> bool { | 
 |     const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E); | 
 |     if (!MTE) return false; | 
 |     const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr()); | 
 |     if (!Num) return false; | 
 |     if (Num->getValue() != 0) return false; | 
 |     return true; | 
 |   }; | 
 |  | 
 |   const Expr *FirstArg = Call->getArg(0); | 
 |   const Expr *SecondArg = Call->getArg(1); | 
 |   const bool IsFirstArgZero = IsLiteralZeroArg(FirstArg); | 
 |   const bool IsSecondArgZero = IsLiteralZeroArg(SecondArg); | 
 |  | 
 |   // Only warn when exactly one argument is zero. | 
 |   if (IsFirstArgZero == IsSecondArgZero) return; | 
 |  | 
 |   SourceRange FirstRange = FirstArg->getSourceRange(); | 
 |   SourceRange SecondRange = SecondArg->getSourceRange(); | 
 |  | 
 |   SourceRange ZeroRange = IsFirstArgZero ? FirstRange : SecondRange; | 
 |  | 
 |   Diag(Call->getExprLoc(), diag::warn_max_unsigned_zero) | 
 |       << IsFirstArgZero << Call->getCallee()->getSourceRange() << ZeroRange; | 
 |  | 
 |   // Deduce what parts to remove so that "std::max(0u, foo)" becomes "(foo)". | 
 |   SourceRange RemovalRange; | 
 |   if (IsFirstArgZero) { | 
 |     RemovalRange = SourceRange(FirstRange.getBegin(), | 
 |                                SecondRange.getBegin().getLocWithOffset(-1)); | 
 |   } else { | 
 |     RemovalRange = SourceRange(getLocForEndOfToken(FirstRange.getEnd()), | 
 |                                SecondRange.getEnd()); | 
 |   } | 
 |  | 
 |   Diag(Call->getExprLoc(), diag::note_remove_max_call) | 
 |         << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()) | 
 |         << FixItHint::CreateRemoval(RemovalRange); | 
 | } | 
 |  | 
 | //===--- CHECK: Standard memory functions ---------------------------------===// | 
 |  | 
 | /// Takes the expression passed to the size_t parameter of functions | 
 | /// such as memcmp, strncat, etc and warns if it's a comparison. | 
 | /// | 
 | /// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`. | 
 | static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, | 
 |                                            const IdentifierInfo *FnName, | 
 |                                            SourceLocation FnLoc, | 
 |                                            SourceLocation RParenLoc) { | 
 |   const auto *Size = dyn_cast<BinaryOperator>(E); | 
 |   if (!Size) | 
 |     return false; | 
 |  | 
 |   // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||: | 
 |   if (!Size->isComparisonOp() && !Size->isLogicalOp()) | 
 |     return false; | 
 |  | 
 |   SourceRange SizeRange = Size->getSourceRange(); | 
 |   S.Diag(Size->getOperatorLoc(), diag::warn_memsize_comparison) | 
 |       << SizeRange << FnName; | 
 |   S.Diag(FnLoc, diag::note_memsize_comparison_paren) | 
 |       << FnName | 
 |       << FixItHint::CreateInsertion( | 
 |              S.getLocForEndOfToken(Size->getLHS()->getEndLoc()), ")") | 
 |       << FixItHint::CreateRemoval(RParenLoc); | 
 |   S.Diag(SizeRange.getBegin(), diag::note_memsize_comparison_cast_silence) | 
 |       << FixItHint::CreateInsertion(SizeRange.getBegin(), "(size_t)(") | 
 |       << FixItHint::CreateInsertion(S.getLocForEndOfToken(SizeRange.getEnd()), | 
 |                                     ")"); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /// Determine whether the given type is or contains a dynamic class type | 
 | /// (e.g., whether it has a vtable). | 
 | static const CXXRecordDecl *getContainedDynamicClass(QualType T, | 
 |                                                      bool &IsContained) { | 
 |   // Look through array types while ignoring qualifiers. | 
 |   const Type *Ty = T->getBaseElementTypeUnsafe(); | 
 |   IsContained = false; | 
 |  | 
 |   const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); | 
 |   RD = RD ? RD->getDefinition() : nullptr; | 
 |   if (!RD || RD->isInvalidDecl()) | 
 |     return nullptr; | 
 |  | 
 |   if (RD->isDynamicClass()) | 
 |     return RD; | 
 |  | 
 |   // Check all the fields.  If any bases were dynamic, the class is dynamic. | 
 |   // It's impossible for a class to transitively contain itself by value, so | 
 |   // infinite recursion is impossible. | 
 |   for (auto *FD : RD->fields()) { | 
 |     bool SubContained; | 
 |     if (const CXXRecordDecl *ContainedRD = | 
 |             getContainedDynamicClass(FD->getType(), SubContained)) { | 
 |       IsContained = true; | 
 |       return ContainedRD; | 
 |     } | 
 |   } | 
 |  | 
 |   return nullptr; | 
 | } | 
 |  | 
 | static const UnaryExprOrTypeTraitExpr *getAsSizeOfExpr(const Expr *E) { | 
 |   if (const auto *Unary = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) | 
 |     if (Unary->getKind() == UETT_SizeOf) | 
 |       return Unary; | 
 |   return nullptr; | 
 | } | 
 |  | 
 | /// If E is a sizeof expression, returns its argument expression, | 
 | /// otherwise returns NULL. | 
 | static const Expr *getSizeOfExprArg(const Expr *E) { | 
 |   if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) | 
 |     if (!SizeOf->isArgumentType()) | 
 |       return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); | 
 |   return nullptr; | 
 | } | 
 |  | 
 | /// If E is a sizeof expression, returns its argument type. | 
 | static QualType getSizeOfArgType(const Expr *E) { | 
 |   if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) | 
 |     return SizeOf->getTypeOfArgument(); | 
 |   return QualType(); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | struct SearchNonTrivialToInitializeField | 
 |     : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> { | 
 |   using Super = | 
 |       DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>; | 
 |  | 
 |   SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {} | 
 |  | 
 |   void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, | 
 |                      SourceLocation SL) { | 
 |     if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { | 
 |       asDerived().visitArray(PDIK, AT, SL); | 
 |       return; | 
 |     } | 
 |  | 
 |     Super::visitWithKind(PDIK, FT, SL); | 
 |   } | 
 |  | 
 |   void visitARCStrong(QualType FT, SourceLocation SL) { | 
 |     S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); | 
 |   } | 
 |   void visitARCWeak(QualType FT, SourceLocation SL) { | 
 |     S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); | 
 |   } | 
 |   void visitStruct(QualType FT, SourceLocation SL) { | 
 |     for (const FieldDecl *FD : FT->castAsRecordDecl()->fields()) | 
 |       visit(FD->getType(), FD->getLocation()); | 
 |   } | 
 |   void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK, | 
 |                   const ArrayType *AT, SourceLocation SL) { | 
 |     visit(getContext().getBaseElementType(AT), SL); | 
 |   } | 
 |   void visitTrivial(QualType FT, SourceLocation SL) {} | 
 |  | 
 |   static void diag(QualType RT, const Expr *E, Sema &S) { | 
 |     SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation()); | 
 |   } | 
 |  | 
 |   ASTContext &getContext() { return S.getASTContext(); } | 
 |  | 
 |   const Expr *E; | 
 |   Sema &S; | 
 | }; | 
 |  | 
 | struct SearchNonTrivialToCopyField | 
 |     : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> { | 
 |   using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>; | 
 |  | 
 |   SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {} | 
 |  | 
 |   void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT, | 
 |                      SourceLocation SL) { | 
 |     if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { | 
 |       asDerived().visitArray(PCK, AT, SL); | 
 |       return; | 
 |     } | 
 |  | 
 |     Super::visitWithKind(PCK, FT, SL); | 
 |   } | 
 |  | 
 |   void visitARCStrong(QualType FT, SourceLocation SL) { | 
 |     S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); | 
 |   } | 
 |   void visitARCWeak(QualType FT, SourceLocation SL) { | 
 |     S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); | 
 |   } | 
 |   void visitPtrAuth(QualType FT, SourceLocation SL) { | 
 |     S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); | 
 |   } | 
 |   void visitStruct(QualType FT, SourceLocation SL) { | 
 |     for (const FieldDecl *FD : FT->castAsRecordDecl()->fields()) | 
 |       visit(FD->getType(), FD->getLocation()); | 
 |   } | 
 |   void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT, | 
 |                   SourceLocation SL) { | 
 |     visit(getContext().getBaseElementType(AT), SL); | 
 |   } | 
 |   void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT, | 
 |                 SourceLocation SL) {} | 
 |   void visitTrivial(QualType FT, SourceLocation SL) {} | 
 |   void visitVolatileTrivial(QualType FT, SourceLocation SL) {} | 
 |  | 
 |   static void diag(QualType RT, const Expr *E, Sema &S) { | 
 |     SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation()); | 
 |   } | 
 |  | 
 |   ASTContext &getContext() { return S.getASTContext(); } | 
 |  | 
 |   const Expr *E; | 
 |   Sema &S; | 
 | }; | 
 |  | 
 | } | 
 |  | 
 | /// Detect if \c SizeofExpr is likely to calculate the sizeof an object. | 
 | static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) { | 
 |   SizeofExpr = SizeofExpr->IgnoreParenImpCasts(); | 
 |  | 
 |   if (const auto *BO = dyn_cast<BinaryOperator>(SizeofExpr)) { | 
 |     if (BO->getOpcode() != BO_Mul && BO->getOpcode() != BO_Add) | 
 |       return false; | 
 |  | 
 |     return doesExprLikelyComputeSize(BO->getLHS()) || | 
 |            doesExprLikelyComputeSize(BO->getRHS()); | 
 |   } | 
 |  | 
 |   return getAsSizeOfExpr(SizeofExpr) != nullptr; | 
 | } | 
 |  | 
 | /// Check if the ArgLoc originated from a macro passed to the call at CallLoc. | 
 | /// | 
 | /// \code | 
 | ///   #define MACRO 0 | 
 | ///   foo(MACRO); | 
 | ///   foo(0); | 
 | /// \endcode | 
 | /// | 
 | /// This should return true for the first call to foo, but not for the second | 
 | /// (regardless of whether foo is a macro or function). | 
 | static bool isArgumentExpandedFromMacro(SourceManager &SM, | 
 |                                         SourceLocation CallLoc, | 
 |                                         SourceLocation ArgLoc) { | 
 |   if (!CallLoc.isMacroID()) | 
 |     return SM.getFileID(CallLoc) != SM.getFileID(ArgLoc); | 
 |  | 
 |   return SM.getFileID(SM.getImmediateMacroCallerLoc(CallLoc)) != | 
 |          SM.getFileID(SM.getImmediateMacroCallerLoc(ArgLoc)); | 
 | } | 
 |  | 
 | /// Diagnose cases like 'memset(buf, sizeof(buf), 0)', which should have the | 
 | /// last two arguments transposed. | 
 | static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) { | 
 |   if (BId != Builtin::BImemset && BId != Builtin::BIbzero) | 
 |     return; | 
 |  | 
 |   const Expr *SizeArg = | 
 |     Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts(); | 
 |  | 
 |   auto isLiteralZero = [](const Expr *E) { | 
 |     return (isa<IntegerLiteral>(E) && | 
 |             cast<IntegerLiteral>(E)->getValue() == 0) || | 
 |            (isa<CharacterLiteral>(E) && | 
 |             cast<CharacterLiteral>(E)->getValue() == 0); | 
 |   }; | 
 |  | 
 |   // If we're memsetting or bzeroing 0 bytes, then this is likely an error. | 
 |   SourceLocation CallLoc = Call->getRParenLoc(); | 
 |   SourceManager &SM = S.getSourceManager(); | 
 |   if (isLiteralZero(SizeArg) && | 
 |       !isArgumentExpandedFromMacro(SM, CallLoc, SizeArg->getExprLoc())) { | 
 |  | 
 |     SourceLocation DiagLoc = SizeArg->getExprLoc(); | 
 |  | 
 |     // Some platforms #define bzero to __builtin_memset. See if this is the | 
 |     // case, and if so, emit a better diagnostic. | 
 |     if (BId == Builtin::BIbzero || | 
 |         (CallLoc.isMacroID() && Lexer::getImmediateMacroName( | 
 |                                     CallLoc, SM, S.getLangOpts()) == "bzero")) { | 
 |       S.Diag(DiagLoc, diag::warn_suspicious_bzero_size); | 
 |       S.Diag(DiagLoc, diag::note_suspicious_bzero_size_silence); | 
 |     } else if (!isLiteralZero(Call->getArg(1)->IgnoreImpCasts())) { | 
 |       S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 0; | 
 |       S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 0; | 
 |     } | 
 |     return; | 
 |   } | 
 |  | 
 |   // If the second argument to a memset is a sizeof expression and the third | 
 |   // isn't, this is also likely an error. This should catch | 
 |   // 'memset(buf, sizeof(buf), 0xff)'. | 
 |   if (BId == Builtin::BImemset && | 
 |       doesExprLikelyComputeSize(Call->getArg(1)) && | 
 |       !doesExprLikelyComputeSize(Call->getArg(2))) { | 
 |     SourceLocation DiagLoc = Call->getArg(1)->getExprLoc(); | 
 |     S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1; | 
 |     S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 1; | 
 |     return; | 
 |   } | 
 | } | 
 |  | 
 | void Sema::CheckMemaccessArguments(const CallExpr *Call, | 
 |                                    unsigned BId, | 
 |                                    IdentifierInfo *FnName) { | 
 |   assert(BId != 0); | 
 |  | 
 |   // It is possible to have a non-standard definition of memset.  Validate | 
 |   // we have enough arguments, and if not, abort further checking. | 
 |   unsigned ExpectedNumArgs = | 
 |       (BId == Builtin::BIstrndup || BId == Builtin::BIbzero ? 2 : 3); | 
 |   if (Call->getNumArgs() < ExpectedNumArgs) | 
 |     return; | 
 |  | 
 |   unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero || | 
 |                       BId == Builtin::BIstrndup ? 1 : 2); | 
 |   unsigned LenArg = | 
 |       (BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); | 
 |   const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); | 
 |  | 
 |   if (CheckMemorySizeofForComparison(*this, LenExpr, FnName, | 
 |                                      Call->getBeginLoc(), Call->getRParenLoc())) | 
 |     return; | 
 |  | 
 |   // Catch cases like 'memset(buf, sizeof(buf), 0)'. | 
 |   CheckMemaccessSize(*this, BId, Call); | 
 |  | 
 |   // We have special checking when the length is a sizeof expression. | 
 |   QualType SizeOfArgTy = getSizeOfArgType(LenExpr); | 
 |   const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); | 
 |   llvm::FoldingSetNodeID SizeOfArgID; | 
 |  | 
 |   // Although widely used, 'bzero' is not a standard function. Be more strict | 
 |   // with the argument types before allowing diagnostics and only allow the | 
 |   // form bzero(ptr, sizeof(...)). | 
 |   QualType FirstArgTy = Call->getArg(0)->IgnoreParenImpCasts()->getType(); | 
 |   if (BId == Builtin::BIbzero && !FirstArgTy->getAs<PointerType>()) | 
 |     return; | 
 |  | 
 |   for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { | 
 |     const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); | 
 |     SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); | 
 |  | 
 |     QualType DestTy = Dest->getType(); | 
 |     QualType PointeeTy; | 
 |     if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { | 
 |       PointeeTy = DestPtrTy->getPointeeType(); | 
 |  | 
 |       // Never warn about void type pointers. This can be used to suppress | 
 |       // false positives. | 
 |       if (PointeeTy->isVoidType()) | 
 |         continue; | 
 |  | 
 |       // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by | 
 |       // actually comparing the expressions for equality. Because computing the | 
 |       // expression IDs can be expensive, we only do this if the diagnostic is | 
 |       // enabled. | 
 |       if (SizeOfArg && | 
 |           !Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, | 
 |                            SizeOfArg->getExprLoc())) { | 
 |         // We only compute IDs for expressions if the warning is enabled, and | 
 |         // cache the sizeof arg's ID. | 
 |         if (SizeOfArgID == llvm::FoldingSetNodeID()) | 
 |           SizeOfArg->Profile(SizeOfArgID, Context, true); | 
 |         llvm::FoldingSetNodeID DestID; | 
 |         Dest->Profile(DestID, Context, true); | 
 |         if (DestID == SizeOfArgID) { | 
 |           // TODO: For strncpy() and friends, this could suggest sizeof(dst) | 
 |           //       over sizeof(src) as well. | 
 |           unsigned ActionIdx = 0; // Default is to suggest dereferencing. | 
 |           StringRef ReadableName = FnName->getName(); | 
 |  | 
 |           if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest)) | 
 |             if (UnaryOp->getOpcode() == UO_AddrOf) | 
 |               ActionIdx = 1; // If its an address-of operator, just remove it. | 
 |           if (!PointeeTy->isIncompleteType() && | 
 |               (Context.getTypeSize(PointeeTy) == Context.getCharWidth())) | 
 |             ActionIdx = 2; // If the pointee's size is sizeof(char), | 
 |                            // suggest an explicit length. | 
 |  | 
 |           // If the function is defined as a builtin macro, do not show macro | 
 |           // expansion. | 
 |           SourceLocation SL = SizeOfArg->getExprLoc(); | 
 |           SourceRange DSR = Dest->getSourceRange(); | 
 |           SourceRange SSR = SizeOfArg->getSourceRange(); | 
 |           SourceManager &SM = getSourceManager(); | 
 |  | 
 |           if (SM.isMacroArgExpansion(SL)) { | 
 |             ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts); | 
 |             SL = SM.getSpellingLoc(SL); | 
 |             DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()), | 
 |                              SM.getSpellingLoc(DSR.getEnd())); | 
 |             SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()), | 
 |                              SM.getSpellingLoc(SSR.getEnd())); | 
 |           } | 
 |  | 
 |           DiagRuntimeBehavior(SL, SizeOfArg, | 
 |                               PDiag(diag::warn_sizeof_pointer_expr_memaccess) | 
 |                                 << ReadableName | 
 |                                 << PointeeTy | 
 |                                 << DestTy | 
 |                                 << DSR | 
 |                                 << SSR); | 
 |           DiagRuntimeBehavior(SL, SizeOfArg, | 
 |                          PDiag(diag::warn_sizeof_pointer_expr_memaccess_note) | 
 |                                 << ActionIdx | 
 |                                 << SSR); | 
 |  | 
 |           break; | 
 |         } | 
 |       } | 
 |  | 
 |       // Also check for cases where the sizeof argument is the exact same | 
 |       // type as the memory argument, and where it points to a user-defined | 
 |       // record type. | 
 |       if (SizeOfArgTy != QualType()) { | 
 |         if (PointeeTy->isRecordType() && | 
 |             Context.typesAreCompatible(SizeOfArgTy, DestTy)) { | 
 |           DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest, | 
 |                               PDiag(diag::warn_sizeof_pointer_type_memaccess) | 
 |                                 << FnName << SizeOfArgTy << ArgIdx | 
 |                                 << PointeeTy << Dest->getSourceRange() | 
 |                                 << LenExpr->getSourceRange()); | 
 |           break; | 
 |         } | 
 |       } | 
 |     } else if (DestTy->isArrayType()) { | 
 |       PointeeTy = DestTy; | 
 |     } | 
 |  | 
 |     if (PointeeTy == QualType()) | 
 |       continue; | 
 |  | 
 |     // Always complain about dynamic classes. | 
 |     bool IsContained; | 
 |     if (const CXXRecordDecl *ContainedRD = | 
 |             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 || IsCmp) { | 
 |         if (BId == Builtin::BImemcpy) | 
 |           OperationType = 1; | 
 |         else if(BId == Builtin::BImemmove) | 
 |           OperationType = 2; | 
 |         else if (IsCmp) | 
 |           OperationType = 3; | 
 |       } | 
 |  | 
 |       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( | 
 |         Dest->getExprLoc(), Dest, | 
 |         PDiag(diag::warn_arc_object_memaccess) | 
 |           << ArgIdx << FnName << PointeeTy | 
 |           << Call->getCallee()->getSourceRange()); | 
 |     else if (const auto *RD = PointeeTy->getAsRecordDecl()) { | 
 |  | 
 |       // FIXME: Do not consider incomplete types even though they may be | 
 |       // completed later. GCC does not diagnose such code, but we may want to | 
 |       // consider diagnosing it in the future, perhaps under a different, but | 
 |       // related, diagnostic group. | 
 |       bool NonTriviallyCopyableCXXRecord = | 
 |           getLangOpts().CPlusPlus && RD->isCompleteDefinition() && | 
 |           !PointeeTy.isTriviallyCopyableType(Context); | 
 |  | 
 |       if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && | 
 |           RD->isNonTrivialToPrimitiveDefaultInitialize()) { | 
 |         DiagRuntimeBehavior(Dest->getExprLoc(), Dest, | 
 |                             PDiag(diag::warn_cstruct_memaccess) | 
 |                                 << ArgIdx << FnName << PointeeTy << 0); | 
 |         SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); | 
 |       } else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && | 
 |                  NonTriviallyCopyableCXXRecord && ArgIdx == 0) { | 
 |         // FIXME: Limiting this warning to dest argument until we decide | 
 |         // whether it's valid for source argument too. | 
 |         DiagRuntimeBehavior(Dest->getExprLoc(), Dest, | 
 |                             PDiag(diag::warn_cxxstruct_memaccess) | 
 |                                 << FnName << PointeeTy); | 
 |       } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && | 
 |                  RD->isNonTrivialToPrimitiveCopy()) { | 
 |         DiagRuntimeBehavior(Dest->getExprLoc(), Dest, | 
 |                             PDiag(diag::warn_cstruct_memaccess) | 
 |                                 << ArgIdx << FnName << PointeeTy << 1); | 
 |         SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this); | 
 |       } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && | 
 |                  NonTriviallyCopyableCXXRecord && ArgIdx == 0) { | 
 |         // FIXME: Limiting this warning to dest argument until we decide | 
 |         // whether it's valid for source argument too. | 
 |         DiagRuntimeBehavior(Dest->getExprLoc(), Dest, | 
 |                             PDiag(diag::warn_cxxstruct_memaccess) | 
 |                                 << FnName << PointeeTy); | 
 |       } else { | 
 |         continue; | 
 |       } | 
 |     } else | 
 |       continue; | 
 |  | 
 |     DiagRuntimeBehavior( | 
 |       Dest->getExprLoc(), Dest, | 
 |       PDiag(diag::note_bad_memaccess_silence) | 
 |         << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); | 
 |     break; | 
 |   } | 
 | } | 
 |  | 
 | // A little helper routine: ignore addition and subtraction of integer literals. | 
 | // This intentionally does not ignore all integer constant expressions because | 
 | // we don't want to remove sizeof(). | 
 | static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { | 
 |   Ex = Ex->IgnoreParenCasts(); | 
 |  | 
 |   while (true) { | 
 |     const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex); | 
 |     if (!BO || !BO->isAdditiveOp()) | 
 |       break; | 
 |  | 
 |     const Expr *RHS = BO->getRHS()->IgnoreParenCasts(); | 
 |     const Expr *LHS = BO->getLHS()->IgnoreParenCasts(); | 
 |  | 
 |     if (isa<IntegerLiteral>(RHS)) | 
 |       Ex = LHS; | 
 |     else if (isa<IntegerLiteral>(LHS)) | 
 |       Ex = RHS; | 
 |     else | 
 |       break; | 
 |   } | 
 |  | 
 |   return Ex; | 
 | } | 
 |  | 
 | static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty, | 
 |                                                       ASTContext &Context) { | 
 |   // Only handle constant-sized or VLAs, but not flexible members. | 
 |   if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) { | 
 |     // Only issue the FIXIT for arrays of size > 1. | 
 |     if (CAT->getZExtSize() <= 1) | 
 |       return false; | 
 |   } else if (!Ty->isVariableArrayType()) { | 
 |     return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void Sema::CheckStrlcpycatArguments(const CallExpr *Call, | 
 |                                     IdentifierInfo *FnName) { | 
 |  | 
 |   // Don't crash if the user has the wrong number of arguments | 
 |   unsigned NumArgs = Call->getNumArgs(); | 
 |   if ((NumArgs != 3) && (NumArgs != 4)) | 
 |     return; | 
 |  | 
 |   const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context); | 
 |   const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context); | 
 |   const Expr *CompareWithSrc = nullptr; | 
 |  | 
 |   if (CheckMemorySizeofForComparison(*this, SizeArg, FnName, | 
 |                                      Call->getBeginLoc(), Call->getRParenLoc())) | 
 |     return; | 
 |  | 
 |   // Look for 'strlcpy(dst, x, sizeof(x))' | 
 |   if (const Expr *Ex = getSizeOfExprArg(SizeArg)) | 
 |     CompareWithSrc = Ex; | 
 |   else { | 
 |     // Look for 'strlcpy(dst, x, strlen(x))' | 
 |     if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) { | 
 |       if (SizeCall->getBuiltinCallee() == Builtin::BIstrlen && | 
 |           SizeCall->getNumArgs() == 1) | 
 |         CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context); | 
 |     } | 
 |   } | 
 |  | 
 |   if (!CompareWithSrc) | 
 |     return; | 
 |  | 
 |   // Determine if the argument to sizeof/strlen is equal to the source | 
 |   // argument.  In principle there's all kinds of things you could do | 
 |   // here, for instance creating an == expression and evaluating it with | 
 |   // EvaluateAsBooleanCondition, but this uses a more direct technique: | 
 |   const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg); | 
 |   if (!SrcArgDRE) | 
 |     return; | 
 |  | 
 |   const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc); | 
 |   if (!CompareWithSrcDRE || | 
 |       SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl()) | 
 |     return; | 
 |  | 
 |   const Expr *OriginalSizeArg = Call->getArg(2); | 
 |   Diag(CompareWithSrcDRE->getBeginLoc(), diag::warn_strlcpycat_wrong_size) | 
 |       << OriginalSizeArg->getSourceRange() << FnName; | 
 |  | 
 |   // Output a FIXIT hint if the destination is an array (rather than a | 
 |   // pointer to an array).  This could be enhanced to handle some | 
 |   // pointers if we know the actual size, like if DstArg is 'array+2' | 
 |   // we could say 'sizeof(array)-2'. | 
 |   const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts(); | 
 |   if (!isConstantSizeArrayWithMoreThanOneElement(DstArg->getType(), Context)) | 
 |     return; | 
 |  | 
 |   SmallString<128> sizeString; | 
 |   llvm::raw_svector_ostream OS(sizeString); | 
 |   OS << "sizeof("; | 
 |   DstArg->printPretty(OS, nullptr, getPrintingPolicy()); | 
 |   OS << ")"; | 
 |  | 
 |   Diag(OriginalSizeArg->getBeginLoc(), diag::note_strlcpycat_wrong_size) | 
 |       << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(), | 
 |                                       OS.str()); | 
 | } | 
 |  | 
 | /// Check if two expressions refer to the same declaration. | 
 | static bool referToTheSameDecl(const Expr *E1, const Expr *E2) { | 
 |   if (const DeclRefExpr *D1 = dyn_cast_or_null<DeclRefExpr>(E1)) | 
 |     if (const DeclRefExpr *D2 = dyn_cast_or_null<DeclRefExpr>(E2)) | 
 |       return D1->getDecl() == D2->getDecl(); | 
 |   return false; | 
 | } | 
 |  | 
 | static const Expr *getStrlenExprArg(const Expr *E) { | 
 |   if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { | 
 |     const FunctionDecl *FD = CE->getDirectCallee(); | 
 |     if (!FD || FD->getMemoryFunctionKind() != Builtin::BIstrlen) | 
 |       return nullptr; | 
 |     return CE->getArg(0)->IgnoreParenCasts(); | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | void Sema::CheckStrncatArguments(const CallExpr *CE, | 
 |                                  const IdentifierInfo *FnName) { | 
 |   // Don't crash if the user has the wrong number of arguments. | 
 |   if (CE->getNumArgs() < 3) | 
 |     return; | 
 |   const Expr *DstArg = CE->getArg(0)->IgnoreParenCasts(); | 
 |   const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts(); | 
 |   const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts(); | 
 |  | 
 |   if (CheckMemorySizeofForComparison(*this, LenArg, FnName, CE->getBeginLoc(), | 
 |                                      CE->getRParenLoc())) | 
 |     return; | 
 |  | 
 |   // Identify common expressions, which are wrongly used as the size argument | 
 |   // to strncat and may lead to buffer overflows. | 
 |   unsigned PatternType = 0; | 
 |   if (const Expr *SizeOfArg = getSizeOfExprArg(LenArg)) { | 
 |     // - sizeof(dst) | 
 |     if (referToTheSameDecl(SizeOfArg, DstArg)) | 
 |       PatternType = 1; | 
 |     // - sizeof(src) | 
 |     else if (referToTheSameDecl(SizeOfArg, SrcArg)) | 
 |       PatternType = 2; | 
 |   } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(LenArg)) { | 
 |     if (BE->getOpcode() == BO_Sub) { | 
 |       const Expr *L = BE->getLHS()->IgnoreParenCasts(); | 
 |       const Expr *R = BE->getRHS()->IgnoreParenCasts(); | 
 |       // - sizeof(dst) - strlen(dst) | 
 |       if (referToTheSameDecl(DstArg, getSizeOfExprArg(L)) && | 
 |           referToTheSameDecl(DstArg, getStrlenExprArg(R))) | 
 |         PatternType = 1; | 
 |       // - sizeof(src) - (anything) | 
 |       else if (referToTheSameDecl(SrcArg, getSizeOfExprArg(L))) | 
 |         PatternType = 2; | 
 |     } | 
 |   } | 
 |  | 
 |   if (PatternType == 0) | 
 |     return; | 
 |  | 
 |   // Generate the diagnostic. | 
 |   SourceLocation SL = LenArg->getBeginLoc(); | 
 |   SourceRange SR = LenArg->getSourceRange(); | 
 |   SourceManager &SM = getSourceManager(); | 
 |  | 
 |   // If the function is defined as a builtin macro, do not show macro expansion. | 
 |   if (SM.isMacroArgExpansion(SL)) { | 
 |     SL = SM.getSpellingLoc(SL); | 
 |     SR = SourceRange(SM.getSpellingLoc(SR.getBegin()), | 
 |                      SM.getSpellingLoc(SR.getEnd())); | 
 |   } | 
 |  | 
 |   // Check if the destination is an array (rather than a pointer to an array). | 
 |   QualType DstTy = DstArg->getType(); | 
 |   bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy, | 
 |                                                                     Context); | 
 |   if (!isKnownSizeArray) { | 
 |     if (PatternType == 1) | 
 |       Diag(SL, diag::warn_strncat_wrong_size) << SR; | 
 |     else | 
 |       Diag(SL, diag::warn_strncat_src_size) << SR; | 
 |     return; | 
 |   } | 
 |  | 
 |   if (PatternType == 1) | 
 |     Diag(SL, diag::warn_strncat_large_size) << SR; | 
 |   else | 
 |     Diag(SL, diag::warn_strncat_src_size) << SR; | 
 |  | 
 |   SmallString<128> sizeString; | 
 |   llvm::raw_svector_ostream OS(sizeString); | 
 |   OS << "sizeof("; | 
 |   DstArg->printPretty(OS, nullptr, getPrintingPolicy()); | 
 |   OS << ") - "; | 
 |   OS << "strlen("; | 
 |   DstArg->printPretty(OS, nullptr, getPrintingPolicy()); | 
 |   OS << ") - 1"; | 
 |  | 
 |   Diag(SL, diag::note_strncat_wrong_size) | 
 |     << FixItHint::CreateReplacement(SR, OS.str()); | 
 | } | 
 |  | 
 | namespace { | 
 | void CheckFreeArgumentsOnLvalue(Sema &S, const std::string &CalleeName, | 
 |                                 const UnaryOperator *UnaryExpr, const Decl *D) { | 
 |   if (isa<FieldDecl, FunctionDecl, VarDecl>(D)) { | 
 |     S.Diag(UnaryExpr->getBeginLoc(), diag::warn_free_nonheap_object) | 
 |         << CalleeName << 0 /*object: */ << cast<NamedDecl>(D); | 
 |     return; | 
 |   } | 
 | } | 
 |  | 
 | void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName, | 
 |                                  const UnaryOperator *UnaryExpr) { | 
 |   if (const auto *Lvalue = dyn_cast<DeclRefExpr>(UnaryExpr->getSubExpr())) { | 
 |     const Decl *D = Lvalue->getDecl(); | 
 |     if (const auto *DD = dyn_cast<DeclaratorDecl>(D)) { | 
 |       if (!DD->getType()->isReferenceType()) | 
 |         return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, D); | 
 |     } | 
 |   } | 
 |  | 
 |   if (const auto *Lvalue = dyn_cast<MemberExpr>(UnaryExpr->getSubExpr())) | 
 |     return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, | 
 |                                       Lvalue->getMemberDecl()); | 
 | } | 
 |  | 
 | void CheckFreeArgumentsPlus(Sema &S, const std::string &CalleeName, | 
 |                             const UnaryOperator *UnaryExpr) { | 
 |   const auto *Lambda = dyn_cast<LambdaExpr>( | 
 |       UnaryExpr->getSubExpr()->IgnoreImplicitAsWritten()->IgnoreParens()); | 
 |   if (!Lambda) | 
 |     return; | 
 |  | 
 |   S.Diag(Lambda->getBeginLoc(), diag::warn_free_nonheap_object) | 
 |       << CalleeName << 2 /*object: lambda expression*/; | 
 | } | 
 |  | 
 | void CheckFreeArgumentsStackArray(Sema &S, const std::string &CalleeName, | 
 |                                   const DeclRefExpr *Lvalue) { | 
 |   const auto *Var = dyn_cast<VarDecl>(Lvalue->getDecl()); | 
 |   if (Var == nullptr) | 
 |     return; | 
 |  | 
 |   S.Diag(Lvalue->getBeginLoc(), diag::warn_free_nonheap_object) | 
 |       << CalleeName << 0 /*object: */ << Var; | 
 | } | 
 |  | 
 | void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName, | 
 |                             const CastExpr *Cast) { | 
 |   SmallString<128> SizeString; | 
 |   llvm::raw_svector_ostream OS(SizeString); | 
 |  | 
 |   clang::CastKind Kind = Cast->getCastKind(); | 
 |   if (Kind == clang::CK_BitCast && | 
 |       !Cast->getSubExpr()->getType()->isFunctionPointerType()) | 
 |     return; | 
 |   if (Kind == clang::CK_IntegralToPointer && | 
 |       !isa<IntegerLiteral>( | 
 |           Cast->getSubExpr()->IgnoreParenImpCasts()->IgnoreParens())) | 
 |     return; | 
 |  | 
 |   switch (Cast->getCastKind()) { | 
 |   case clang::CK_BitCast: | 
 |   case clang::CK_IntegralToPointer: | 
 |   case clang::CK_FunctionToPointerDecay: | 
 |     OS << '\''; | 
 |     Cast->printPretty(OS, nullptr, S.getPrintingPolicy()); | 
 |     OS << '\''; | 
 |     break; | 
 |   default: | 
 |     return; | 
 |   } | 
 |  | 
 |   S.Diag(Cast->getBeginLoc(), diag::warn_free_nonheap_object) | 
 |       << CalleeName << 0 /*object: */ << OS.str(); | 
 | } | 
 | } // namespace | 
 |  | 
 | void Sema::CheckFreeArguments(const CallExpr *E) { | 
 |   const std::string CalleeName = | 
 |       cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString(); | 
 |  | 
 |   { // Prefer something that doesn't involve a cast to make things simpler. | 
 |     const Expr *Arg = E->getArg(0)->IgnoreParenCasts(); | 
 |     if (const auto *UnaryExpr = dyn_cast<UnaryOperator>(Arg)) | 
 |       switch (UnaryExpr->getOpcode()) { | 
 |       case UnaryOperator::Opcode::UO_AddrOf: | 
 |         return CheckFreeArgumentsAddressof(*this, CalleeName, UnaryExpr); | 
 |       case UnaryOperator::Opcode::UO_Plus: | 
 |         return CheckFreeArgumentsPlus(*this, CalleeName, UnaryExpr); | 
 |       default: | 
 |         break; | 
 |       } | 
 |  | 
 |     if (const auto *Lvalue = dyn_cast<DeclRefExpr>(Arg)) | 
 |       if (Lvalue->getType()->isArrayType()) | 
 |         return CheckFreeArgumentsStackArray(*this, CalleeName, Lvalue); | 
 |  | 
 |     if (const auto *Label = dyn_cast<AddrLabelExpr>(Arg)) { | 
 |       Diag(Label->getBeginLoc(), diag::warn_free_nonheap_object) | 
 |           << CalleeName << 0 /*object: */ << Label->getLabel()->getIdentifier(); | 
 |       return; | 
 |     } | 
 |  | 
 |     if (isa<BlockExpr>(Arg)) { | 
 |       Diag(Arg->getBeginLoc(), diag::warn_free_nonheap_object) | 
 |           << CalleeName << 1 /*object: block*/; | 
 |       return; | 
 |     } | 
 |   } | 
 |   // Maybe the cast was important, check after the other cases. | 
 |   if (const auto *Cast = dyn_cast<CastExpr>(E->getArg(0))) | 
 |     return CheckFreeArgumentsCast(*this, CalleeName, Cast); | 
 | } | 
 |  | 
 | void | 
 | Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, | 
 |                          SourceLocation ReturnLoc, | 
 |                          bool isObjCMethod, | 
 |                          const AttrVec *Attrs, | 
 |                          const FunctionDecl *FD) { | 
 |   // Check if the return value is null but should not be. | 
 |   if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || | 
 |        (!isObjCMethod && isNonNullType(lhsType))) && | 
 |       CheckNonNullExpr(*this, RetValExp)) | 
 |     Diag(ReturnLoc, diag::warn_null_ret) | 
 |       << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange(); | 
 |  | 
 |   // C++11 [basic.stc.dynamic.allocation]p4: | 
 |   //   If an allocation function declared with a non-throwing | 
 |   //   exception-specification fails to allocate storage, it shall return | 
 |   //   a null pointer. Any other allocation function that fails to allocate | 
 |   //   storage shall indicate failure only by throwing an exception [...] | 
 |   if (FD) { | 
 |     OverloadedOperatorKind Op = FD->getOverloadedOperator(); | 
 |     if (Op == OO_New || Op == OO_Array_New) { | 
 |       const FunctionProtoType *Proto | 
 |         = FD->getType()->castAs<FunctionProtoType>(); | 
 |       if (!Proto->isNothrow(/*ResultIfDependent*/true) && | 
 |           CheckNonNullExpr(*this, RetValExp)) | 
 |         Diag(ReturnLoc, diag::warn_operator_new_returns_null) | 
 |           << FD << getLangOpts().CPlusPlus11; | 
 |     } | 
 |   } | 
 |  | 
 |   if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) { | 
 |     Diag(ReturnLoc, diag::err_wasm_table_art) << 1; | 
 |   } | 
 |  | 
 |   // PPC MMA non-pointer types are not allowed as return type. Checking the type | 
 |   // here prevent the user from using a PPC MMA type as trailing return type. | 
 |   if (Context.getTargetInfo().getTriple().isPPC64()) | 
 |     PPC().CheckPPCMMAType(RetValExp->getType(), ReturnLoc); | 
 | } | 
 |  | 
 | void Sema::CheckFloatComparison(SourceLocation Loc, const Expr *LHS, | 
 |                                 const Expr *RHS, BinaryOperatorKind Opcode) { | 
 |   if (!BinaryOperator::isEqualityOp(Opcode)) | 
 |     return; | 
 |  | 
 |   // Match and capture subexpressions such as "(float) X == 0.1". | 
 |   const FloatingLiteral *FPLiteral; | 
 |   const CastExpr *FPCast; | 
 |   auto getCastAndLiteral = [&FPLiteral, &FPCast](const Expr *L, const Expr *R) { | 
 |     FPLiteral = dyn_cast<FloatingLiteral>(L->IgnoreParens()); | 
 |     FPCast = dyn_cast<CastExpr>(R->IgnoreParens()); | 
 |     return FPLiteral && FPCast; | 
 |   }; | 
 |  | 
 |   if (getCastAndLiteral(LHS, RHS) || getCastAndLiteral(RHS, LHS)) { | 
 |     auto *SourceTy = FPCast->getSubExpr()->getType()->getAs<BuiltinType>(); | 
 |     auto *TargetTy = FPLiteral->getType()->getAs<BuiltinType>(); | 
 |     if (SourceTy && TargetTy && SourceTy->isFloatingPoint() && | 
 |         TargetTy->isFloatingPoint()) { | 
 |       bool Lossy; | 
 |       llvm::APFloat TargetC = FPLiteral->getValue(); | 
 |       TargetC.convert(Context.getFloatTypeSemantics(QualType(SourceTy, 0)), | 
 |                       llvm::APFloat::rmNearestTiesToEven, &Lossy); | 
 |       if (Lossy) { | 
 |         // If the literal cannot be represented in the source type, then a | 
 |         // check for == is always false and check for != is always true. | 
 |         Diag(Loc, diag::warn_float_compare_literal) | 
 |             << (Opcode == BO_EQ) << QualType(SourceTy, 0) | 
 |             << LHS->getSourceRange() << RHS->getSourceRange(); | 
 |         return; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Match a more general floating-point equality comparison (-Wfloat-equal). | 
 |   const Expr *LeftExprSansParen = LHS->IgnoreParenImpCasts(); | 
 |   const Expr *RightExprSansParen = RHS->IgnoreParenImpCasts(); | 
 |  | 
 |   // Special case: check for x == x (which is OK). | 
 |   // Do not emit warnings for such cases. | 
 |   if (const auto *DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen)) | 
 |     if (const auto *DRR = dyn_cast<DeclRefExpr>(RightExprSansParen)) | 
 |       if (DRL->getDecl() == DRR->getDecl()) | 
 |         return; | 
 |  | 
 |   // Special case: check for comparisons against literals that can be exactly | 
 |   //  represented by APFloat.  In such cases, do not emit a warning.  This | 
 |   //  is a heuristic: often comparison against such literals are used to | 
 |   //  detect if a value in a variable has not changed.  This clearly can | 
 |   //  lead to false negatives. | 
 |   if (const auto *FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) { | 
 |     if (FLL->isExact()) | 
 |       return; | 
 |   } else if (const auto *FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)) | 
 |     if (FLR->isExact()) | 
 |       return; | 
 |  | 
 |   // Check for comparisons with builtin types. | 
 |   if (const auto *CL = dyn_cast<CallExpr>(LeftExprSansParen); | 
 |       CL && CL->getBuiltinCallee()) | 
 |     return; | 
 |  | 
 |   if (const auto *CR = dyn_cast<CallExpr>(RightExprSansParen); | 
 |       CR && CR->getBuiltinCallee()) | 
 |     return; | 
 |  | 
 |   // Emit the diagnostic. | 
 |   Diag(Loc, diag::warn_floatingpoint_eq) | 
 |     << LHS->getSourceRange() << RHS->getSourceRange(); | 
 | } | 
 |  | 
 | //===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===// | 
 | //===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===// | 
 |  | 
 | namespace { | 
 |  | 
 | /// Structure recording the 'active' range of an integer-valued | 
 | /// expression. | 
 | struct IntRange { | 
 |   /// The number of bits active in the int. Note that this includes exactly one | 
 |   /// sign bit if !NonNegative. | 
 |   unsigned Width; | 
 |  | 
 |   /// True if the int is known not to have negative values. If so, all leading | 
 |   /// bits before Width are known zero, otherwise they are known to be the | 
 |   /// same as the MSB within Width. | 
 |   bool NonNegative; | 
 |  | 
 |   IntRange(unsigned Width, bool NonNegative) | 
 |       : Width(Width), NonNegative(NonNegative) {} | 
 |  | 
 |   /// Number of bits excluding the sign bit. | 
 |   unsigned valueBits() const { | 
 |     return NonNegative ? Width : Width - 1; | 
 |   } | 
 |  | 
 |   /// Returns the range of the bool type. | 
 |   static IntRange forBoolType() { | 
 |     return IntRange(1, true); | 
 |   } | 
 |  | 
 |   /// Returns the range of an opaque value of the given integral type. | 
 |   static IntRange forValueOfType(ASTContext &C, QualType T) { | 
 |     return forValueOfCanonicalType(C, | 
 |                           T->getCanonicalTypeInternal().getTypePtr()); | 
 |   } | 
 |  | 
 |   /// Returns the range of an opaque value of a canonical integral type. | 
 |   static IntRange forValueOfCanonicalType(ASTContext &C, const Type *T) { | 
 |     assert(T->isCanonicalUnqualified()); | 
 |  | 
 |     if (const auto *VT = dyn_cast<VectorType>(T)) | 
 |       T = VT->getElementType().getTypePtr(); | 
 |     if (const auto *CT = dyn_cast<ComplexType>(T)) | 
 |       T = CT->getElementType().getTypePtr(); | 
 |     if (const auto *AT = dyn_cast<AtomicType>(T)) | 
 |       T = AT->getValueType().getTypePtr(); | 
 |  | 
 |     if (!C.getLangOpts().CPlusPlus) { | 
 |       // For enum types in C code, use the underlying datatype. | 
 |       if (const auto *ED = T->getAsEnumDecl()) | 
 |         T = ED->getIntegerType().getDesugaredType(C).getTypePtr(); | 
 |     } else if (auto *Enum = T->getAsEnumDecl()) { | 
 |       // For enum types in C++, use the known bit width of the enumerators. | 
 |       // In C++11, enums can have a fixed underlying type. Use this type to | 
 |       // compute the range. | 
 |       if (Enum->isFixed()) { | 
 |         return IntRange(C.getIntWidth(QualType(T, 0)), | 
 |                         !Enum->getIntegerType()->isSignedIntegerType()); | 
 |       } | 
 |  | 
 |       unsigned NumPositive = Enum->getNumPositiveBits(); | 
 |       unsigned NumNegative = Enum->getNumNegativeBits(); | 
 |  | 
 |       if (NumNegative == 0) | 
 |         return IntRange(NumPositive, true/*NonNegative*/); | 
 |       else | 
 |         return IntRange(std::max(NumPositive + 1, NumNegative), | 
 |                         false/*NonNegative*/); | 
 |     } | 
 |  | 
 |     if (const auto *EIT = dyn_cast<BitIntType>(T)) | 
 |       return IntRange(EIT->getNumBits(), EIT->isUnsigned()); | 
 |  | 
 |     const BuiltinType *BT = cast<BuiltinType>(T); | 
 |     assert(BT->isInteger()); | 
 |  | 
 |     return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); | 
 |   } | 
 |  | 
 |   /// Returns the "target" range of a canonical integral type, i.e. | 
 |   /// the range of values expressible in the type. | 
 |   /// | 
 |   /// This matches forValueOfCanonicalType except that enums have the | 
 |   /// full range of their type, not the range of their enumerators. | 
 |   static IntRange forTargetOfCanonicalType(ASTContext &C, const Type *T) { | 
 |     assert(T->isCanonicalUnqualified()); | 
 |  | 
 |     if (const VectorType *VT = dyn_cast<VectorType>(T)) | 
 |       T = VT->getElementType().getTypePtr(); | 
 |     if (const ComplexType *CT = dyn_cast<ComplexType>(T)) | 
 |       T = CT->getElementType().getTypePtr(); | 
 |     if (const AtomicType *AT = dyn_cast<AtomicType>(T)) | 
 |       T = AT->getValueType().getTypePtr(); | 
 |     if (const auto *ED = T->getAsEnumDecl()) | 
 |       T = C.getCanonicalType(ED->getIntegerType()).getTypePtr(); | 
 |  | 
 |     if (const auto *EIT = dyn_cast<BitIntType>(T)) | 
 |       return IntRange(EIT->getNumBits(), EIT->isUnsigned()); | 
 |  | 
 |     const BuiltinType *BT = cast<BuiltinType>(T); | 
 |     assert(BT->isInteger()); | 
 |  | 
 |     return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); | 
 |   } | 
 |  | 
 |   /// Returns the supremum of two ranges: i.e. their conservative merge. | 
 |   static IntRange join(IntRange L, IntRange R) { | 
 |     bool Unsigned = L.NonNegative && R.NonNegative; | 
 |     return IntRange(std::max(L.valueBits(), R.valueBits()) + !Unsigned, | 
 |                     L.NonNegative && R.NonNegative); | 
 |   } | 
 |  | 
 |   /// Return the range of a bitwise-AND of the two ranges. | 
 |   static IntRange bit_and(IntRange L, IntRange R) { | 
 |     unsigned Bits = std::max(L.Width, R.Width); | 
 |     bool NonNegative = false; | 
 |     if (L.NonNegative) { | 
 |       Bits = std::min(Bits, L.Width); | 
 |       NonNegative = true; | 
 |     } | 
 |     if (R.NonNegative) { | 
 |       Bits = std::min(Bits, R.Width); | 
 |       NonNegative = true; | 
 |     } | 
 |     return IntRange(Bits, NonNegative); | 
 |   } | 
 |  | 
 |   /// Return the range of a sum of the two ranges. | 
 |   static IntRange sum(IntRange L, IntRange R) { | 
 |     bool Unsigned = L.NonNegative && R.NonNegative; | 
 |     return IntRange(std::max(L.valueBits(), R.valueBits()) + 1 + !Unsigned, | 
 |                     Unsigned); | 
 |   } | 
 |  | 
 |   /// Return the range of a difference of the two ranges. | 
 |   static IntRange difference(IntRange L, IntRange R) { | 
 |     // We need a 1-bit-wider range if: | 
 |     //   1) LHS can be negative: least value can be reduced. | 
 |     //   2) RHS can be negative: greatest value can be increased. | 
 |     bool CanWiden = !L.NonNegative || !R.NonNegative; | 
 |     bool Unsigned = L.NonNegative && R.Width == 0; | 
 |     return IntRange(std::max(L.valueBits(), R.valueBits()) + CanWiden + | 
 |                         !Unsigned, | 
 |                     Unsigned); | 
 |   } | 
 |  | 
 |   /// Return the range of a product of the two ranges. | 
 |   static IntRange product(IntRange L, IntRange R) { | 
 |     // If both LHS and RHS can be negative, we can form | 
 |     //   -2^L * -2^R = 2^(L + R) | 
 |     // which requires L + R + 1 value bits to represent. | 
 |     bool CanWiden = !L.NonNegative && !R.NonNegative; | 
 |     bool Unsigned = L.NonNegative && R.NonNegative; | 
 |     return IntRange(L.valueBits() + R.valueBits() + CanWiden + !Unsigned, | 
 |                     Unsigned); | 
 |   } | 
 |  | 
 |   /// Return the range of a remainder operation between the two ranges. | 
 |   static IntRange rem(IntRange L, IntRange R) { | 
 |     // The result of a remainder can't be larger than the result of | 
 |     // either side. The sign of the result is the sign of the LHS. | 
 |     bool Unsigned = L.NonNegative; | 
 |     return IntRange(std::min(L.valueBits(), R.valueBits()) + !Unsigned, | 
 |                     Unsigned); | 
 |   } | 
 | }; | 
 |  | 
 | } // namespace | 
 |  | 
 | static IntRange GetValueRange(llvm::APSInt &value, unsigned MaxWidth) { | 
 |   if (value.isSigned() && value.isNegative()) | 
 |     return IntRange(value.getSignificantBits(), false); | 
 |  | 
 |   if (value.getBitWidth() > MaxWidth) | 
 |     value = value.trunc(MaxWidth); | 
 |  | 
 |   // isNonNegative() just checks the sign bit without considering | 
 |   // signedness. | 
 |   return IntRange(value.getActiveBits(), true); | 
 | } | 
 |  | 
 | static IntRange GetValueRange(APValue &result, QualType Ty, unsigned MaxWidth) { | 
 |   if (result.isInt()) | 
 |     return GetValueRange(result.getInt(), MaxWidth); | 
 |  | 
 |   if (result.isVector()) { | 
 |     IntRange R = GetValueRange(result.getVectorElt(0), Ty, MaxWidth); | 
 |     for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) { | 
 |       IntRange El = GetValueRange(result.getVectorElt(i), Ty, MaxWidth); | 
 |       R = IntRange::join(R, El); | 
 |     } | 
 |     return R; | 
 |   } | 
 |  | 
 |   if (result.isComplexInt()) { | 
 |     IntRange R = GetValueRange(result.getComplexIntReal(), MaxWidth); | 
 |     IntRange I = GetValueRange(result.getComplexIntImag(), MaxWidth); | 
 |     return IntRange::join(R, I); | 
 |   } | 
 |  | 
 |   // This can happen with lossless casts to intptr_t of "based" lvalues. | 
 |   // Assume it might use arbitrary bits. | 
 |   // FIXME: The only reason we need to pass the type in here is to get | 
 |   // the sign right on this one case.  It would be nice if APValue | 
 |   // preserved this. | 
 |   assert(result.isLValue() || result.isAddrLabelDiff()); | 
 |   return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); | 
 | } | 
 |  | 
 | static QualType GetExprType(const Expr *E) { | 
 |   QualType Ty = E->getType(); | 
 |   if (const auto *AtomicRHS = Ty->getAs<AtomicType>()) | 
 |     Ty = AtomicRHS->getValueType(); | 
 |   return Ty; | 
 | } | 
 |  | 
 | /// Attempts to estimate an approximate range for the given integer expression. | 
 | /// Returns a range if successful, otherwise it returns \c std::nullopt if a | 
 | /// reliable estimation cannot be determined. | 
 | /// | 
 | /// \param MaxWidth The width to which the value will be truncated. | 
 | /// \param InConstantContext If \c true, interpret the expression within a | 
 | ///        constant context. | 
 | /// \param Approximate If \c true, provide a likely range of values by assuming | 
 | ///        that arithmetic on narrower types remains within those types. | 
 | ///        If \c false, return a range that includes all possible values | 
 | ///        resulting from the expression. | 
 | /// \returns A range of values that the expression might take, or | 
 | ///          std::nullopt if a reliable estimation cannot be determined. | 
 | static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E, | 
 |                                                unsigned MaxWidth, | 
 |                                                bool InConstantContext, | 
 |                                                bool Approximate) { | 
 |   E = E->IgnoreParens(); | 
 |  | 
 |   // Try a full evaluation first. | 
 |   Expr::EvalResult result; | 
 |   if (E->EvaluateAsRValue(result, C, InConstantContext)) | 
 |     return GetValueRange(result.Val, GetExprType(E), MaxWidth); | 
 |  | 
 |   // I think we only want to look through implicit casts here; if the | 
 |   // user has an explicit widening cast, we should treat the value as | 
 |   // being of the new, wider type. | 
 |   if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) { | 
 |     if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue) | 
 |       return TryGetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext, | 
 |                              Approximate); | 
 |  | 
 |     IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE)); | 
 |  | 
 |     bool isIntegerCast = CE->getCastKind() == CK_IntegralCast || | 
 |                          CE->getCastKind() == CK_BooleanToSignedIntegral; | 
 |  | 
 |     // Assume that non-integer casts can span the full range of the type. | 
 |     if (!isIntegerCast) | 
 |       return OutputTypeRange; | 
 |  | 
 |     std::optional<IntRange> SubRange = TryGetExprRange( | 
 |         C, CE->getSubExpr(), std::min(MaxWidth, OutputTypeRange.Width), | 
 |         InConstantContext, Approximate); | 
 |     if (!SubRange) | 
 |       return std::nullopt; | 
 |  | 
 |     // Bail out if the subexpr's range is as wide as the cast type. | 
 |     if (SubRange->Width >= OutputTypeRange.Width) | 
 |       return OutputTypeRange; | 
 |  | 
 |     // Otherwise, we take the smaller width, and we're non-negative if | 
 |     // either the output type or the subexpr is. | 
 |     return IntRange(SubRange->Width, | 
 |                     SubRange->NonNegative || OutputTypeRange.NonNegative); | 
 |   } | 
 |  | 
 |   if (const auto *CO = dyn_cast<ConditionalOperator>(E)) { | 
 |     // If we can fold the condition, just take that operand. | 
 |     bool CondResult; | 
 |     if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) | 
 |       return TryGetExprRange( | 
 |           C, CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), MaxWidth, | 
 |           InConstantContext, Approximate); | 
 |  | 
 |     // Otherwise, conservatively merge. | 
 |     // TryGetExprRange requires an integer expression, but a throw expression | 
 |     // results in a void type. | 
 |     Expr *TrueExpr = CO->getTrueExpr(); | 
 |     if (TrueExpr->getType()->isVoidType()) | 
 |       return std::nullopt; | 
 |  | 
 |     std::optional<IntRange> L = | 
 |         TryGetExprRange(C, TrueExpr, MaxWidth, InConstantContext, Approximate); | 
 |     if (!L) | 
 |       return std::nullopt; | 
 |  | 
 |     Expr *FalseExpr = CO->getFalseExpr(); | 
 |     if (FalseExpr->getType()->isVoidType()) | 
 |       return std::nullopt; | 
 |  | 
 |     std::optional<IntRange> R = | 
 |         TryGetExprRange(C, FalseExpr, MaxWidth, InConstantContext, Approximate); | 
 |     if (!R) | 
 |       return std::nullopt; | 
 |  | 
 |     return IntRange::join(*L, *R); | 
 |   } | 
 |  | 
 |   if (const auto *BO = dyn_cast<BinaryOperator>(E)) { | 
 |     IntRange (*Combine)(IntRange, IntRange) = IntRange::join; | 
 |  | 
 |     switch (BO->getOpcode()) { | 
 |     case BO_Cmp: | 
 |       llvm_unreachable("builtin <=> should have class type"); | 
 |  | 
 |     // Boolean-valued operations are single-bit and positive. | 
 |     case BO_LAnd: | 
 |     case BO_LOr: | 
 |     case BO_LT: | 
 |     case BO_GT: | 
 |     case BO_LE: | 
 |     case BO_GE: | 
 |     case BO_EQ: | 
 |     case BO_NE: | 
 |       return IntRange::forBoolType(); | 
 |  | 
 |     // The type of the assignments is the type of the LHS, so the RHS | 
 |     // is not necessarily the same type. | 
 |     case BO_MulAssign: | 
 |     case BO_DivAssign: | 
 |     case BO_RemAssign: | 
 |     case BO_AddAssign: | 
 |     case BO_SubAssign: | 
 |     case BO_XorAssign: | 
 |     case BO_OrAssign: | 
 |       // TODO: bitfields? | 
 |       return IntRange::forValueOfType(C, GetExprType(E)); | 
 |  | 
 |     // Simple assignments just pass through the RHS, which will have | 
 |     // been coerced to the LHS type. | 
 |     case BO_Assign: | 
 |       // TODO: bitfields? | 
 |       return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext, | 
 |                              Approximate); | 
 |  | 
 |     // Operations with opaque sources are black-listed. | 
 |     case BO_PtrMemD: | 
 |     case BO_PtrMemI: | 
 |       return IntRange::forValueOfType(C, GetExprType(E)); | 
 |  | 
 |     // Bitwise-and uses the *infinum* of the two source ranges. | 
 |     case BO_And: | 
 |     case BO_AndAssign: | 
 |       Combine = IntRange::bit_and; | 
 |       break; | 
 |  | 
 |     // Left shift gets black-listed based on a judgement call. | 
 |     case BO_Shl: | 
 |       // ...except that we want to treat '1 << (blah)' as logically | 
 |       // positive.  It's an important idiom. | 
 |       if (IntegerLiteral *I | 
 |             = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) { | 
 |         if (I->getValue() == 1) { | 
 |           IntRange R = IntRange::forValueOfType(C, GetExprType(E)); | 
 |           return IntRange(R.Width, /*NonNegative*/ true); | 
 |         } | 
 |       } | 
 |       [[fallthrough]]; | 
 |  | 
 |     case BO_ShlAssign: | 
 |       return IntRange::forValueOfType(C, GetExprType(E)); | 
 |  | 
 |     // Right shift by a constant can narrow its left argument. | 
 |     case BO_Shr: | 
 |     case BO_ShrAssign: { | 
 |       std::optional<IntRange> L = TryGetExprRange( | 
 |           C, BO->getLHS(), MaxWidth, InConstantContext, Approximate); | 
 |       if (!L) | 
 |         return std::nullopt; | 
 |  | 
 |       // If the shift amount is a positive constant, drop the width by | 
 |       // that much. | 
 |       if (std::optional<llvm::APSInt> shift = | 
 |               BO->getRHS()->getIntegerConstantExpr(C)) { | 
 |         if (shift->isNonNegative()) { | 
 |           if (shift->uge(L->Width)) | 
 |             L->Width = (L->NonNegative ? 0 : 1); | 
 |           else | 
 |             L->Width -= shift->getZExtValue(); | 
 |         } | 
 |       } | 
 |  | 
 |       return L; | 
 |     } | 
 |  | 
 |     // Comma acts as its right operand. | 
 |     case BO_Comma: | 
 |       return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext, | 
 |                              Approximate); | 
 |  | 
 |     case BO_Add: | 
 |       if (!Approximate) | 
 |         Combine = IntRange::sum; | 
 |       break; | 
 |  | 
 |     case BO_Sub: | 
 |       if (BO->getLHS()->getType()->isPointerType()) | 
 |         return IntRange::forValueOfType(C, GetExprType(E)); | 
 |       if (!Approximate) | 
 |         Combine = IntRange::difference; | 
 |       break; | 
 |  | 
 |     case BO_Mul: | 
 |       if (!Approximate) | 
 |         Combine = IntRange::product; | 
 |       break; | 
 |  | 
 |     // The width of a division result is mostly determined by the size | 
 |     // of the LHS. | 
 |     case BO_Div: { | 
 |       // Don't 'pre-truncate' the operands. | 
 |       unsigned opWidth = C.getIntWidth(GetExprType(E)); | 
 |       std::optional<IntRange> L = TryGetExprRange( | 
 |           C, BO->getLHS(), opWidth, InConstantContext, Approximate); | 
 |       if (!L) | 
 |         return std::nullopt; | 
 |  | 
 |       // If the divisor is constant, use that. | 
 |       if (std::optional<llvm::APSInt> divisor = | 
 |               BO->getRHS()->getIntegerConstantExpr(C)) { | 
 |         unsigned log2 = divisor->logBase2(); // floor(log_2(divisor)) | 
 |         if (log2 >= L->Width) | 
 |           L->Width = (L->NonNegative ? 0 : 1); | 
 |         else | 
 |           L->Width = std::min(L->Width - log2, MaxWidth); | 
 |         return L; | 
 |       } | 
 |  | 
 |       // Otherwise, just use the LHS's width. | 
 |       // FIXME: This is wrong if the LHS could be its minimal value and the RHS | 
 |       // could be -1. | 
 |       std::optional<IntRange> R = TryGetExprRange( | 
 |           C, BO->getRHS(), opWidth, InConstantContext, Approximate); | 
 |       if (!R) | 
 |         return std::nullopt; | 
 |  | 
 |       return IntRange(L->Width, L->NonNegative && R->NonNegative); | 
 |     } | 
 |  | 
 |     case BO_Rem: | 
 |       Combine = IntRange::rem; | 
 |       break; | 
 |  | 
 |     // The default behavior is okay for these. | 
 |     case BO_Xor: | 
 |     case BO_Or: | 
 |       break; | 
 |     } | 
 |  | 
 |     // Combine the two ranges, but limit the result to the type in which we | 
 |     // performed the computation. | 
 |     QualType T = GetExprType(E); | 
 |     unsigned opWidth = C.getIntWidth(T); | 
 |     std::optional<IntRange> L = TryGetExprRange(C, BO->getLHS(), opWidth, | 
 |                                                 InConstantContext, Approximate); | 
 |     if (!L) | 
 |       return std::nullopt; | 
 |  | 
 |     std::optional<IntRange> R = TryGetExprRange(C, BO->getRHS(), opWidth, | 
 |                                                 InConstantContext, Approximate); | 
 |     if (!R) | 
 |       return std::nullopt; | 
 |  | 
 |     IntRange C = Combine(*L, *R); | 
 |     C.NonNegative |= T->isUnsignedIntegerOrEnumerationType(); | 
 |     C.Width = std::min(C.Width, MaxWidth); | 
 |     return C; | 
 |   } | 
 |  | 
 |   if (const auto *UO = dyn_cast<UnaryOperator>(E)) { | 
 |     switch (UO->getOpcode()) { | 
 |     // Boolean-valued operations are white-listed. | 
 |     case UO_LNot: | 
 |       return IntRange::forBoolType(); | 
 |  | 
 |     // Operations with opaque sources are black-listed. | 
 |     case UO_Deref: | 
 |     case UO_AddrOf: // should be impossible | 
 |       return IntRange::forValueOfType(C, GetExprType(E)); | 
 |  | 
 |     case UO_Minus: { | 
 |       if (E->getType()->isUnsignedIntegerType()) { | 
 |         return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext, | 
 |                                Approximate); | 
 |       } | 
 |  | 
 |       std::optional<IntRange> SubRange = TryGetExprRange( | 
 |           C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate); | 
 |  | 
 |       if (!SubRange) | 
 |         return std::nullopt; | 
 |  | 
 |       // If the range was previously non-negative, we need an extra bit for the | 
 |       // sign bit. Otherwise, we need an extra bit because the negation of the | 
 |       // most-negative value is one bit wider than that value. | 
 |       return IntRange(std::min(SubRange->Width + 1, MaxWidth), false); | 
 |     } | 
 |  | 
 |     case UO_Not: { | 
 |       if (E->getType()->isUnsignedIntegerType()) { | 
 |         return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext, | 
 |                                Approximate); | 
 |       } | 
 |  | 
 |       std::optional<IntRange> SubRange = TryGetExprRange( | 
 |           C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate); | 
 |  | 
 |       if (!SubRange) | 
 |         return std::nullopt; | 
 |  | 
 |       // The width increments by 1 if the sub-expression cannot be negative | 
 |       // since it now can be. | 
 |       return IntRange( | 
 |           std::min(SubRange->Width + (int)SubRange->NonNegative, MaxWidth), | 
 |           false); | 
 |     } | 
 |  | 
 |     default: | 
 |       return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext, | 
 |                              Approximate); | 
 |     } | 
 |   } | 
 |  | 
 |   if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) | 
 |     return TryGetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext, | 
 |                            Approximate); | 
 |  | 
 |   if (const auto *BitField = E->getSourceBitField()) | 
 |     return IntRange(BitField->getBitWidthValue(), | 
 |                     BitField->getType()->isUnsignedIntegerOrEnumerationType()); | 
 |  | 
 |   if (GetExprType(E)->isVoidType()) | 
 |     return std::nullopt; | 
 |  | 
 |   return IntRange::forValueOfType(C, GetExprType(E)); | 
 | } | 
 |  | 
 | static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E, | 
 |                                                bool InConstantContext, | 
 |                                                bool Approximate) { | 
 |   return TryGetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext, | 
 |                          Approximate); | 
 | } | 
 |  | 
 | /// Checks whether the given value, which currently has the given | 
 | /// source semantics, has the same value when coerced through the | 
 | /// target semantics. | 
 | static bool IsSameFloatAfterCast(const llvm::APFloat &value, | 
 |                                  const llvm::fltSemantics &Src, | 
 |                                  const llvm::fltSemantics &Tgt) { | 
 |   llvm::APFloat truncated = value; | 
 |  | 
 |   bool ignored; | 
 |   truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); | 
 |   truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); | 
 |  | 
 |   return truncated.bitwiseIsEqual(value); | 
 | } | 
 |  | 
 | /// Checks whether the given value, which currently has the given | 
 | /// source semantics, has the same value when coerced through the | 
 | /// target semantics. | 
 | /// | 
 | /// The value might be a vector of floats (or a complex number). | 
 | static bool IsSameFloatAfterCast(const APValue &value, | 
 |                                  const llvm::fltSemantics &Src, | 
 |                                  const llvm::fltSemantics &Tgt) { | 
 |   if (value.isFloat()) | 
 |     return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); | 
 |  | 
 |   if (value.isVector()) { | 
 |     for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) | 
 |       if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) | 
 |         return false; | 
 |     return true; | 
 |   } | 
 |  | 
 |   assert(value.isComplexFloat()); | 
 |   return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && | 
 |           IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); | 
 | } | 
 |  | 
 | static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC, | 
 |                                        bool IsListInit = false); | 
 |  | 
 | static bool IsEnumConstOrFromMacro(Sema &S, const Expr *E) { | 
 |   // Suppress cases where we are comparing against an enum constant. | 
 |   if (const auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) | 
 |     if (isa<EnumConstantDecl>(DR->getDecl())) | 
 |       return true; | 
 |  | 
 |   // Suppress cases where the value is expanded from a macro, unless that macro | 
 |   // is how a language represents a boolean literal. This is the case in both C | 
 |   // and Objective-C. | 
 |   SourceLocation BeginLoc = E->getBeginLoc(); | 
 |   if (BeginLoc.isMacroID()) { | 
 |     StringRef MacroName = Lexer::getImmediateMacroName( | 
 |         BeginLoc, S.getSourceManager(), S.getLangOpts()); | 
 |     return MacroName != "YES" && MacroName != "NO" && | 
 |            MacroName != "true" && MacroName != "false"; | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | static bool isKnownToHaveUnsignedValue(const Expr *E) { | 
 |   return E->getType()->isIntegerType() && | 
 |          (!E->getType()->isSignedIntegerType() || | 
 |           !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType()); | 
 | } | 
 |  | 
 | namespace { | 
 | /// The promoted range of values of a type. In general this has the | 
 | /// following structure: | 
 | /// | 
 | ///     |-----------| . . . |-----------| | 
 | ///     ^           ^       ^           ^ | 
 | ///    Min       HoleMin  HoleMax      Max | 
 | /// | 
 | /// ... where there is only a hole if a signed type is promoted to unsigned | 
 | /// (in which case Min and Max are the smallest and largest representable | 
 | /// values). | 
 | struct PromotedRange { | 
 |   // Min, or HoleMax if there is a hole. | 
 |   llvm::APSInt PromotedMin; | 
 |   // Max, or HoleMin if there is a hole. | 
 |   llvm::APSInt PromotedMax; | 
 |  | 
 |   PromotedRange(IntRange R, unsigned BitWidth, bool Unsigned) { | 
 |     if (R.Width == 0) | 
 |       PromotedMin = PromotedMax = llvm::APSInt(BitWidth, Unsigned); | 
 |     else if (R.Width >= BitWidth && !Unsigned) { | 
 |       // Promotion made the type *narrower*. This happens when promoting | 
 |       // a < 32-bit unsigned / <= 32-bit signed bit-field to 'signed int'. | 
 |       // Treat all values of 'signed int' as being in range for now. | 
 |       PromotedMin = llvm::APSInt::getMinValue(BitWidth, Unsigned); | 
 |       PromotedMax = llvm::APSInt::getMaxValue(BitWidth, Unsigned); | 
 |     } else { | 
 |       PromotedMin = llvm::APSInt::getMinValue(R.Width, R.NonNegative) | 
 |                         .extOrTrunc(BitWidth); | 
 |       PromotedMin.setIsUnsigned(Unsigned); | 
 |  | 
 |       PromotedMax = llvm::APSInt::getMaxValue(R.Width, R.NonNegative) | 
 |                         .extOrTrunc(BitWidth); | 
 |       PromotedMax.setIsUnsigned(Unsigned); | 
 |     } | 
 |   } | 
 |  | 
 |   // Determine whether this range is contiguous (has no hole). | 
 |   bool isContiguous() const { return PromotedMin <= PromotedMax; } | 
 |  | 
 |   // Where a constant value is within the range. | 
 |   enum ComparisonResult { | 
 |     LT = 0x1, | 
 |     LE = 0x2, | 
 |     GT = 0x4, | 
 |     GE = 0x8, | 
 |     EQ = 0x10, | 
 |     NE = 0x20, | 
 |     InRangeFlag = 0x40, | 
 |  | 
 |     Less = LE | LT | NE, | 
 |     Min = LE | InRangeFlag, | 
 |     InRange = InRangeFlag, | 
 |     Max = GE | InRangeFlag, | 
 |     Greater = GE | GT | NE, | 
 |  | 
 |     OnlyValue = LE | GE | EQ | InRangeFlag, | 
 |     InHole = NE | 
 |   }; | 
 |  | 
 |   ComparisonResult compare(const llvm::APSInt &Value) const { | 
 |     assert(Value.getBitWidth() == PromotedMin.getBitWidth() && | 
 |            Value.isUnsigned() == PromotedMin.isUnsigned()); | 
 |     if (!isContiguous()) { | 
 |       assert(Value.isUnsigned() && "discontiguous range for signed compare"); | 
 |       if (Value.isMinValue()) return Min; | 
 |       if (Value.isMaxValue()) return Max; | 
 |       if (Value >= PromotedMin) return InRange; | 
 |       if (Value <= PromotedMax) return InRange; | 
 |       return InHole; | 
 |     } | 
 |  | 
 |     switch (llvm::APSInt::compareValues(Value, PromotedMin)) { | 
 |     case -1: return Less; | 
 |     case 0: return PromotedMin == PromotedMax ? OnlyValue : Min; | 
 |     case 1: | 
 |       switch (llvm::APSInt::compareValues(Value, PromotedMax)) { | 
 |       case -1: return InRange; | 
 |       case 0: return Max; | 
 |       case 1: return Greater; | 
 |       } | 
 |     } | 
 |  | 
 |     llvm_unreachable("impossible compare result"); | 
 |   } | 
 |  | 
 |   static std::optional<StringRef> | 
 |   constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) { | 
 |     if (Op == BO_Cmp) { | 
 |       ComparisonResult LTFlag = LT, GTFlag = GT; | 
 |       if (ConstantOnRHS) std::swap(LTFlag, GTFlag); | 
 |  | 
 |       if (R & EQ) return StringRef("'std::strong_ordering::equal'"); | 
 |       if (R & LTFlag) return StringRef("'std::strong_ordering::less'"); | 
 |       if (R & GTFlag) return StringRef("'std::strong_ordering::greater'"); | 
 |       return std::nullopt; | 
 |     } | 
 |  | 
 |     ComparisonResult TrueFlag, FalseFlag; | 
 |     if (Op == BO_EQ) { | 
 |       TrueFlag = EQ; | 
 |       FalseFlag = NE; | 
 |     } else if (Op == BO_NE) { | 
 |       TrueFlag = NE; | 
 |       FalseFlag = EQ; | 
 |     } else { | 
 |       if ((Op == BO_LT || Op == BO_GE) ^ ConstantOnRHS) { | 
 |         TrueFlag = LT; | 
 |         FalseFlag = GE; | 
 |       } else { | 
 |         TrueFlag = GT; | 
 |         FalseFlag = LE; | 
 |       } | 
 |       if (Op == BO_GE || Op == BO_LE) | 
 |         std::swap(TrueFlag, FalseFlag); | 
 |     } | 
 |     if (R & TrueFlag) | 
 |       return StringRef("true"); | 
 |     if (R & FalseFlag) | 
 |       return StringRef("false"); | 
 |     return std::nullopt; | 
 |   } | 
 | }; | 
 | } | 
 |  | 
 | static bool HasEnumType(const Expr *E) { | 
 |   // Strip off implicit integral promotions. | 
 |   while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) { | 
 |     if (ICE->getCastKind() != CK_IntegralCast && | 
 |         ICE->getCastKind() != CK_NoOp) | 
 |       break; | 
 |     E = ICE->getSubExpr(); | 
 |   } | 
 |  | 
 |   return E->getType()->isEnumeralType(); | 
 | } | 
 |  | 
 | static int classifyConstantValue(Expr *Constant) { | 
 |   // The values of this enumeration are used in the diagnostics | 
 |   // diag::warn_out_of_range_compare and diag::warn_tautological_bool_compare. | 
 |   enum ConstantValueKind { | 
 |     Miscellaneous = 0, | 
 |     LiteralTrue, | 
 |     LiteralFalse | 
 |   }; | 
 |   if (auto *BL = dyn_cast<CXXBoolLiteralExpr>(Constant)) | 
 |     return BL->getValue() ? ConstantValueKind::LiteralTrue | 
 |                           : ConstantValueKind::LiteralFalse; | 
 |   return ConstantValueKind::Miscellaneous; | 
 | } | 
 |  | 
 | static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, | 
 |                                         Expr *Constant, Expr *Other, | 
 |                                         const llvm::APSInt &Value, | 
 |                                         bool RhsConstant) { | 
 |   if (S.inTemplateInstantiation()) | 
 |     return false; | 
 |  | 
 |   Expr *OriginalOther = Other; | 
 |  | 
 |   Constant = Constant->IgnoreParenImpCasts(); | 
 |   Other = Other->IgnoreParenImpCasts(); | 
 |  | 
 |   // Suppress warnings on tautological comparisons between values of the same | 
 |   // enumeration type. There are only two ways we could warn on this: | 
 |   //  - If the constant is outside the range of representable values of | 
 |   //    the enumeration. In such a case, we should warn about the cast | 
 |   //    to enumeration type, not about the comparison. | 
 |   //  - If the constant is the maximum / minimum in-range value. For an | 
 |   //    enumeratin type, such comparisons can be meaningful and useful. | 
 |   if (Constant->getType()->isEnumeralType() && | 
 |       S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType())) | 
 |     return false; | 
 |  | 
 |   std::optional<IntRange> OtherValueRange = TryGetExprRange( | 
 |       S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/false); | 
 |   if (!OtherValueRange) | 
 |     return false; | 
 |  | 
 |   QualType OtherT = Other->getType(); | 
 |   if (const auto *AT = OtherT->getAs<AtomicType>()) | 
 |     OtherT = AT->getValueType(); | 
 |   IntRange OtherTypeRange = IntRange::forValueOfType(S.Context, OtherT); | 
 |  | 
 |   // Special case for ObjC BOOL on targets where its a typedef for a signed char | 
 |   // (Namely, macOS). FIXME: IntRange::forValueOfType should do this. | 
 |   bool IsObjCSignedCharBool = S.getLangOpts().ObjC && | 
 |                               S.ObjC().NSAPIObj->isObjCBOOLType(OtherT) && | 
 |                               OtherT->isSpecificBuiltinType(BuiltinType::SChar); | 
 |  | 
 |   // Whether we're treating Other as being a bool because of the form of | 
 |   // expression despite it having another type (typically 'int' in C). | 
 |   bool OtherIsBooleanDespiteType = | 
 |       !OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue(); | 
 |   if (OtherIsBooleanDespiteType || IsObjCSignedCharBool) | 
 |     OtherTypeRange = *OtherValueRange = IntRange::forBoolType(); | 
 |  | 
 |   // Check if all values in the range of possible values of this expression | 
 |   // lead to the same comparison outcome. | 
 |   PromotedRange OtherPromotedValueRange(*OtherValueRange, Value.getBitWidth(), | 
 |                                         Value.isUnsigned()); | 
 |   auto Cmp = OtherPromotedValueRange.compare(Value); | 
 |   auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant); | 
 |   if (!Result) | 
 |     return false; | 
 |  | 
 |   // Also consider the range determined by the type alone. This allows us to | 
 |   // classify the warning under the proper diagnostic group. | 
 |   bool TautologicalTypeCompare = false; | 
 |   { | 
 |     PromotedRange OtherPromotedTypeRange(OtherTypeRange, Value.getBitWidth(), | 
 |                                          Value.isUnsigned()); | 
 |     auto TypeCmp = OtherPromotedTypeRange.compare(Value); | 
 |     if (auto TypeResult = PromotedRange::constantValue(E->getOpcode(), TypeCmp, | 
 |                                                        RhsConstant)) { | 
 |       TautologicalTypeCompare = true; | 
 |       Cmp = TypeCmp; | 
 |       Result = TypeResult; | 
 |     } | 
 |   } | 
 |  | 
 |   // Don't warn if the non-constant operand actually always evaluates to the | 
 |   // same value. | 
 |   if (!TautologicalTypeCompare && OtherValueRange->Width == 0) | 
 |     return false; | 
 |  | 
 |   // Suppress the diagnostic for an in-range comparison if the constant comes | 
 |   // from a macro or enumerator. We don't want to diagnose | 
 |   // | 
 |   //   some_long_value <= INT_MAX | 
 |   // | 
 |   // when sizeof(int) == sizeof(long). | 
 |   bool InRange = Cmp & PromotedRange::InRangeFlag; | 
 |   if (InRange && IsEnumConstOrFromMacro(S, Constant)) | 
 |     return false; | 
 |  | 
 |   // A comparison of an unsigned bit-field against 0 is really a type problem, | 
 |   // even though at the type level the bit-field might promote to 'signed int'. | 
 |   if (Other->refersToBitField() && InRange && Value == 0 && | 
 |       Other->getType()->isUnsignedIntegerOrEnumerationType()) | 
 |     TautologicalTypeCompare = true; | 
 |  | 
 |   // If this is a comparison to an enum constant, include that | 
 |   // constant in the diagnostic. | 
 |   const EnumConstantDecl *ED = nullptr; | 
 |   if (const auto *DR = dyn_cast<DeclRefExpr>(Constant)) | 
 |     ED = dyn_cast<EnumConstantDecl>(DR->getDecl()); | 
 |  | 
 |   // Should be enough for uint128 (39 decimal digits) | 
 |   SmallString<64> PrettySourceValue; | 
 |   llvm::raw_svector_ostream OS(PrettySourceValue); | 
 |   if (ED) { | 
 |     OS << '\'' << *ED << "' (" << Value << ")"; | 
 |   } else if (auto *BL = dyn_cast<ObjCBoolLiteralExpr>( | 
 |                Constant->IgnoreParenImpCasts())) { | 
 |     OS << (BL->getValue() ? "YES" : "NO"); | 
 |   } else { | 
 |     OS << Value; | 
 |   } | 
 |  | 
 |   if (!TautologicalTypeCompare) { | 
 |     S.Diag(E->getOperatorLoc(), diag::warn_tautological_compare_value_range) | 
 |         << RhsConstant << OtherValueRange->Width << OtherValueRange->NonNegative | 
 |         << E->getOpcodeStr() << OS.str() << *Result | 
 |         << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (IsObjCSignedCharBool) { | 
 |     S.DiagRuntimeBehavior(E->getOperatorLoc(), E, | 
 |                           S.PDiag(diag::warn_tautological_compare_objc_bool) | 
 |                               << OS.str() << *Result); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // FIXME: We use a somewhat different formatting for the in-range cases and | 
 |   // cases involving boolean values for historical reasons. We should pick a | 
 |   // consistent way of presenting these diagnostics. | 
 |   if (!InRange || Other->isKnownToHaveBooleanValue()) { | 
 |  | 
 |     S.DiagRuntimeBehavior( | 
 |         E->getOperatorLoc(), E, | 
 |         S.PDiag(!InRange ? diag::warn_out_of_range_compare | 
 |                          : diag::warn_tautological_bool_compare) | 
 |             << OS.str() << classifyConstantValue(Constant) << OtherT | 
 |             << OtherIsBooleanDespiteType << *Result | 
 |             << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); | 
 |   } else { | 
 |     bool IsCharTy = OtherT.withoutLocalFastQualifiers() == S.Context.CharTy; | 
 |     unsigned Diag = | 
 |         (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) | 
 |             ? (HasEnumType(OriginalOther) | 
 |                    ? diag::warn_unsigned_enum_always_true_comparison | 
 |                    : IsCharTy ? diag::warn_unsigned_char_always_true_comparison | 
 |                               : diag::warn_unsigned_always_true_comparison) | 
 |             : diag::warn_tautological_constant_compare; | 
 |  | 
 |     S.Diag(E->getOperatorLoc(), Diag) | 
 |         << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result | 
 |         << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /// Analyze the operands of the given comparison.  Implements the | 
 | /// fallback case from AnalyzeComparison. | 
 | static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { | 
 |   AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); | 
 |   AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); | 
 | } | 
 |  | 
 | /// Implements -Wsign-compare. | 
 | /// | 
 | /// \param E the binary operator to check for warnings | 
 | static void AnalyzeComparison(Sema &S, BinaryOperator *E) { | 
 |   // The type the comparison is being performed in. | 
 |   QualType T = E->getLHS()->getType(); | 
 |  | 
 |   // Only analyze comparison operators where both sides have been converted to | 
 |   // the same type. | 
 |   if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())) | 
 |     return AnalyzeImpConvsInComparison(S, E); | 
 |  | 
 |   // Don't analyze value-dependent comparisons directly. | 
 |   if (E->isValueDependent()) | 
 |     return AnalyzeImpConvsInComparison(S, E); | 
 |  | 
 |   Expr *LHS = E->getLHS(); | 
 |   Expr *RHS = E->getRHS(); | 
 |  | 
 |   if (T->isIntegralType(S.Context)) { | 
 |     std::optional<llvm::APSInt> RHSValue = | 
 |         RHS->getIntegerConstantExpr(S.Context); | 
 |     std::optional<llvm::APSInt> LHSValue = | 
 |         LHS->getIntegerConstantExpr(S.Context); | 
 |  | 
 |     // We don't care about expressions whose result is a constant. | 
 |     if (RHSValue && LHSValue) | 
 |       return AnalyzeImpConvsInComparison(S, E); | 
 |  | 
 |     // We only care about expressions where just one side is literal | 
 |     if ((bool)RHSValue ^ (bool)LHSValue) { | 
 |       // Is the constant on the RHS or LHS? | 
 |       const bool RhsConstant = (bool)RHSValue; | 
 |       Expr *Const = RhsConstant ? RHS : LHS; | 
 |       Expr *Other = RhsConstant ? LHS : RHS; | 
 |       const llvm::APSInt &Value = RhsConstant ? *RHSValue : *LHSValue; | 
 |  | 
 |       // Check whether an integer constant comparison results in a value | 
 |       // of 'true' or 'false'. | 
 |       if (CheckTautologicalComparison(S, E, Const, Other, Value, RhsConstant)) | 
 |         return AnalyzeImpConvsInComparison(S, E); | 
 |     } | 
 |   } | 
 |  | 
 |   if (!T->hasUnsignedIntegerRepresentation()) { | 
 |     // We don't do anything special if this isn't an unsigned integral | 
 |     // comparison:  we're only interested in integral comparisons, and | 
 |     // signed comparisons only happen in cases we don't care to warn about. | 
 |     return AnalyzeImpConvsInComparison(S, E); | 
 |   } | 
 |  | 
 |   LHS = LHS->IgnoreParenImpCasts(); | 
 |   RHS = RHS->IgnoreParenImpCasts(); | 
 |  | 
 |   if (!S.getLangOpts().CPlusPlus) { | 
 |     // Avoid warning about comparison of integers with different signs when | 
 |     // RHS/LHS has a `typeof(E)` type whose sign is different from the sign of | 
 |     // the type of `E`. | 
 |     if (const auto *TET = dyn_cast<TypeOfExprType>(LHS->getType())) | 
 |       LHS = TET->getUnderlyingExpr()->IgnoreParenImpCasts(); | 
 |     if (const auto *TET = dyn_cast<TypeOfExprType>(RHS->getType())) | 
 |       RHS = TET->getUnderlyingExpr()->IgnoreParenImpCasts(); | 
 |   } | 
 |  | 
 |   // Check to see if one of the (unmodified) operands is of different | 
 |   // signedness. | 
 |   Expr *signedOperand, *unsignedOperand; | 
 |   if (LHS->getType()->hasSignedIntegerRepresentation()) { | 
 |     assert(!RHS->getType()->hasSignedIntegerRepresentation() && | 
 |            "unsigned comparison between two signed integer expressions?"); | 
 |     signedOperand = LHS; | 
 |     unsignedOperand = RHS; | 
 |   } else if (RHS->getType()->hasSignedIntegerRepresentation()) { | 
 |     signedOperand = RHS; | 
 |     unsignedOperand = LHS; | 
 |   } else { | 
 |     return AnalyzeImpConvsInComparison(S, E); | 
 |   } | 
 |  | 
 |   // Otherwise, calculate the effective range of the signed operand. | 
 |   std::optional<IntRange> signedRange = | 
 |       TryGetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(), | 
 |                       /*Approximate=*/true); | 
 |   if (!signedRange) | 
 |     return; | 
 |  | 
 |   // Go ahead and analyze implicit conversions in the operands.  Note | 
 |   // that we skip the implicit conversions on both sides. | 
 |   AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc()); | 
 |   AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); | 
 |  | 
 |   // If the signed range is non-negative, -Wsign-compare won't fire. | 
 |   if (signedRange->NonNegative) | 
 |     return; | 
 |  | 
 |   // For (in)equality comparisons, if the unsigned operand is a | 
 |   // constant which cannot collide with a overflowed signed operand, | 
 |   // then reinterpreting the signed operand as unsigned will not | 
 |   // change the result of the comparison. | 
 |   if (E->isEqualityOp()) { | 
 |     unsigned comparisonWidth = S.Context.getIntWidth(T); | 
 |     std::optional<IntRange> unsignedRange = TryGetExprRange( | 
 |         S.Context, unsignedOperand, S.isConstantEvaluatedContext(), | 
 |         /*Approximate=*/true); | 
 |     if (!unsignedRange) | 
 |       return; | 
 |  | 
 |     // We should never be unable to prove that the unsigned operand is | 
 |     // non-negative. | 
 |     assert(unsignedRange->NonNegative && "unsigned range includes negative?"); | 
 |  | 
 |     if (unsignedRange->Width < comparisonWidth) | 
 |       return; | 
 |   } | 
 |  | 
 |   S.DiagRuntimeBehavior(E->getOperatorLoc(), E, | 
 |                         S.PDiag(diag::warn_mixed_sign_comparison) | 
 |                             << LHS->getType() << RHS->getType() | 
 |                             << LHS->getSourceRange() << RHS->getSourceRange()); | 
 | } | 
 |  | 
 | /// Analyzes an attempt to assign the given value to a bitfield. | 
 | /// | 
 | /// Returns true if there was something fishy about the attempt. | 
 | static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, | 
 |                                       SourceLocation InitLoc) { | 
 |   assert(Bitfield->isBitField()); | 
 |   if (Bitfield->isInvalidDecl()) | 
 |     return false; | 
 |  | 
 |   // White-list bool bitfields. | 
 |   QualType BitfieldType = Bitfield->getType(); | 
 |   if (BitfieldType->isBooleanType()) | 
 |      return false; | 
 |  | 
 |   if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) { | 
 |     // If the underlying enum type was not explicitly specified as an unsigned | 
 |     // type and the enum contain only positive values, MSVC++ will cause an | 
 |     // inconsistency by storing this as a signed type. | 
 |     if (S.getLangOpts().CPlusPlus11 && | 
 |         !BitfieldEnumDecl->getIntegerTypeSourceInfo() && | 
 |         BitfieldEnumDecl->getNumPositiveBits() > 0 && | 
 |         BitfieldEnumDecl->getNumNegativeBits() == 0) { | 
 |       S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield) | 
 |           << BitfieldEnumDecl; | 
 |     } | 
 |   } | 
 |  | 
 |   // Ignore value- or type-dependent expressions. | 
 |   if (Bitfield->getBitWidth()->isValueDependent() || | 
 |       Bitfield->getBitWidth()->isTypeDependent() || | 
 |       Init->isValueDependent() || | 
 |       Init->isTypeDependent()) | 
 |     return false; | 
 |  | 
 |   Expr *OriginalInit = Init->IgnoreParenImpCasts(); | 
 |   unsigned FieldWidth = Bitfield->getBitWidthValue(); | 
 |  | 
 |   Expr::EvalResult Result; | 
 |   if (!OriginalInit->EvaluateAsInt(Result, S.Context, | 
 |                                    Expr::SE_AllowSideEffects)) { | 
 |     // The RHS is not constant.  If the RHS has an enum type, make sure the | 
 |     // bitfield is wide enough to hold all the values of the enum without | 
 |     // truncation. | 
 |     const auto *ED = OriginalInit->getType()->getAsEnumDecl(); | 
 |     const PreferredTypeAttr *PTAttr = nullptr; | 
 |     if (!ED) { | 
 |       PTAttr = Bitfield->getAttr<PreferredTypeAttr>(); | 
 |       if (PTAttr) | 
 |         ED = PTAttr->getType()->getAsEnumDecl(); | 
 |     } | 
 |     if (ED) { | 
 |       bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType(); | 
 |  | 
 |       // Enum types are implicitly signed on Windows, so check if there are any | 
 |       // negative enumerators to see if the enum was intended to be signed or | 
 |       // not. | 
 |       bool SignedEnum = ED->getNumNegativeBits() > 0; | 
 |  | 
 |       // Check for surprising sign changes when assigning enum values to a | 
 |       // bitfield of different signedness.  If the bitfield is signed and we | 
 |       // have exactly the right number of bits to store this unsigned enum, | 
 |       // suggest changing the enum to an unsigned type. This typically happens | 
 |       // on Windows where unfixed enums always use an underlying type of 'int'. | 
 |       unsigned DiagID = 0; | 
 |       if (SignedEnum && !SignedBitfield) { | 
 |         DiagID = | 
 |             PTAttr == nullptr | 
 |                 ? diag::warn_unsigned_bitfield_assigned_signed_enum | 
 |                 : diag:: | 
 |                       warn_preferred_type_unsigned_bitfield_assigned_signed_enum; | 
 |       } else if (SignedBitfield && !SignedEnum && | 
 |                  ED->getNumPositiveBits() == FieldWidth) { | 
 |         DiagID = | 
 |             PTAttr == nullptr | 
 |                 ? diag::warn_signed_bitfield_enum_conversion | 
 |                 : diag::warn_preferred_type_signed_bitfield_enum_conversion; | 
 |       } | 
 |       if (DiagID) { | 
 |         S.Diag(InitLoc, DiagID) << Bitfield << ED; | 
 |         TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo(); | 
 |         SourceRange TypeRange = | 
 |             TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange(); | 
 |         S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign) | 
 |             << SignedEnum << TypeRange; | 
 |         if (PTAttr) | 
 |           S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type) | 
 |               << ED; | 
 |       } | 
 |  | 
 |       // Compute the required bitwidth. If the enum has negative values, we need | 
 |       // one more bit than the normal number of positive bits to represent the | 
 |       // sign bit. | 
 |       unsigned BitsNeeded = SignedEnum ? std::max(ED->getNumPositiveBits() + 1, | 
 |                                                   ED->getNumNegativeBits()) | 
 |                                        : ED->getNumPositiveBits(); | 
 |  | 
 |       // Check the bitwidth. | 
 |       if (BitsNeeded > FieldWidth) { | 
 |         Expr *WidthExpr = Bitfield->getBitWidth(); | 
 |         auto DiagID = | 
 |             PTAttr == nullptr | 
 |                 ? diag::warn_bitfield_too_small_for_enum | 
 |                 : diag::warn_preferred_type_bitfield_too_small_for_enum; | 
 |         S.Diag(InitLoc, DiagID) << Bitfield << ED; | 
 |         S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield) | 
 |             << BitsNeeded << ED << WidthExpr->getSourceRange(); | 
 |         if (PTAttr) | 
 |           S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type) | 
 |               << ED; | 
 |       } | 
 |     } | 
 |  | 
 |     return false; | 
 |   } | 
 |  | 
 |   llvm::APSInt Value = Result.Val.getInt(); | 
 |  | 
 |   unsigned OriginalWidth = Value.getBitWidth(); | 
 |  | 
 |   // In C, the macro 'true' from stdbool.h will evaluate to '1'; To reduce | 
 |   // false positives where the user is demonstrating they intend to use the | 
 |   // bit-field as a Boolean, check to see if the value is 1 and we're assigning | 
 |   // to a one-bit bit-field to see if the value came from a macro named 'true'. | 
 |   bool OneAssignedToOneBitBitfield = FieldWidth == 1 && Value == 1; | 
 |   if (OneAssignedToOneBitBitfield && !S.LangOpts.CPlusPlus) { | 
 |     SourceLocation MaybeMacroLoc = OriginalInit->getBeginLoc(); | 
 |     if (S.SourceMgr.isInSystemMacro(MaybeMacroLoc) && | 
 |         S.findMacroSpelling(MaybeMacroLoc, "true")) | 
 |       return false; | 
 |   } | 
 |  | 
 |   if (!Value.isSigned() || Value.isNegative()) | 
 |     if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit)) | 
 |       if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not) | 
 |         OriginalWidth = Value.getSignificantBits(); | 
 |  | 
 |   if (OriginalWidth <= FieldWidth) | 
 |     return false; | 
 |  | 
 |   // Compute the value which the bitfield will contain. | 
 |   llvm::APSInt TruncatedValue = Value.trunc(FieldWidth); | 
 |   TruncatedValue.setIsSigned(BitfieldType->isSignedIntegerType()); | 
 |  | 
 |   // Check whether the stored value is equal to the original value. | 
 |   TruncatedValue = TruncatedValue.extend(OriginalWidth); | 
 |   if (llvm::APSInt::isSameValue(Value, TruncatedValue)) | 
 |     return false; | 
 |  | 
 |   std::string PrettyValue = toString(Value, 10); | 
 |   std::string PrettyTrunc = toString(TruncatedValue, 10); | 
 |  | 
 |   S.Diag(InitLoc, OneAssignedToOneBitBitfield | 
 |                       ? diag::warn_impcast_single_bit_bitield_precision_constant | 
 |                       : diag::warn_impcast_bitfield_precision_constant) | 
 |       << PrettyValue << PrettyTrunc << OriginalInit->getType() | 
 |       << Init->getSourceRange(); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /// Analyze the given simple or compound assignment for warning-worthy | 
 | /// operations. | 
 | static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { | 
 |   // Just recurse on the LHS. | 
 |   AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); | 
 |  | 
 |   // We want to recurse on the RHS as normal unless we're assigning to | 
 |   // a bitfield. | 
 |   if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) { | 
 |     if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(), | 
 |                                   E->getOperatorLoc())) { | 
 |       // Recurse, ignoring any implicit conversions on the RHS. | 
 |       return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(), | 
 |                                         E->getOperatorLoc()); | 
 |     } | 
 |   } | 
 |  | 
 |   AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); | 
 |  | 
 |   // Diagnose implicitly sequentially-consistent atomic assignment. | 
 |   if (E->getLHS()->getType()->isAtomicType()) | 
 |     S.Diag(E->getRHS()->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); | 
 | } | 
 |  | 
 | /// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion. | 
 | static void DiagnoseImpCast(Sema &S, const Expr *E, QualType SourceType, | 
 |                             QualType T, SourceLocation CContext, unsigned diag, | 
 |                             bool PruneControlFlow = false) { | 
 |   // For languages like HLSL and OpenCL, implicit conversion diagnostics listing | 
 |   // address space annotations isn't really useful. The warnings aren't because | 
 |   // you're converting a `private int` to `unsigned int`, it is because you're | 
 |   // conerting `int` to `unsigned int`. | 
 |   if (SourceType.hasAddressSpace()) | 
 |     SourceType = S.getASTContext().removeAddrSpaceQualType(SourceType); | 
 |   if (T.hasAddressSpace()) | 
 |     T = S.getASTContext().removeAddrSpaceQualType(T); | 
 |   if (PruneControlFlow) { | 
 |     S.DiagRuntimeBehavior(E->getExprLoc(), E, | 
 |                           S.PDiag(diag) | 
 |                               << SourceType << T << E->getSourceRange() | 
 |                               << SourceRange(CContext)); | 
 |     return; | 
 |   } | 
 |   S.Diag(E->getExprLoc(), diag) | 
 |     << SourceType << T << E->getSourceRange() << SourceRange(CContext); | 
 | } | 
 |  | 
 | /// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion. | 
 | static void DiagnoseImpCast(Sema &S, const Expr *E, QualType T, | 
 |                             SourceLocation CContext, unsigned diag, | 
 |                             bool PruneControlFlow = false) { | 
 |   DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, PruneControlFlow); | 
 | } | 
 |  | 
 | /// Diagnose an implicit cast from a floating point value to an integer value. | 
 | static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T, | 
 |                                     SourceLocation CContext) { | 
 |   bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); | 
 |   bool PruneWarnings = S.inTemplateInstantiation(); | 
 |  | 
 |   const Expr *InnerE = E->IgnoreParenImpCasts(); | 
 |   // We also want to warn on, e.g., "int i = -1.234" | 
 |   if (const auto *UOp = dyn_cast<UnaryOperator>(InnerE)) | 
 |     if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) | 
 |       InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); | 
 |  | 
 |   bool IsLiteral = isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE); | 
 |  | 
 |   llvm::APFloat Value(0.0); | 
 |   bool IsConstant = | 
 |     E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); | 
 |   if (!IsConstant) { | 
 |     if (S.ObjC().isSignedCharBool(T)) { | 
 |       return S.ObjC().adornBoolConversionDiagWithTernaryFixit( | 
 |           E, S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool) | 
 |                  << E->getType()); | 
 |     } | 
 |  | 
 |     return DiagnoseImpCast(S, E, T, CContext, | 
 |                            diag::warn_impcast_float_integer, PruneWarnings); | 
 |   } | 
 |  | 
 |   bool isExact = false; | 
 |  | 
 |   llvm::APSInt IntegerValue(S.Context.getIntWidth(T), | 
 |                             T->hasUnsignedIntegerRepresentation()); | 
 |   llvm::APFloat::opStatus Result = Value.convertToInteger( | 
 |       IntegerValue, llvm::APFloat::rmTowardZero, &isExact); | 
 |  | 
 |   // FIXME: Force the precision of the source value down so we don't print | 
 |   // digits which are usually useless (we don't really care here if we | 
 |   // truncate a digit by accident in edge cases).  Ideally, APFloat::toString | 
 |   // would automatically print the shortest representation, but it's a bit | 
 |   // tricky to implement. | 
 |   SmallString<16> PrettySourceValue; | 
 |   unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics()); | 
 |   precision = (precision * 59 + 195) / 196; | 
 |   Value.toString(PrettySourceValue, precision); | 
 |  | 
 |   if (S.ObjC().isSignedCharBool(T) && IntegerValue != 0 && IntegerValue != 1) { | 
 |     return S.ObjC().adornBoolConversionDiagWithTernaryFixit( | 
 |         E, S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool) | 
 |                << PrettySourceValue); | 
 |   } | 
 |  | 
 |   if (Result == llvm::APFloat::opOK && isExact) { | 
 |     if (IsLiteral) return; | 
 |     return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, | 
 |                            PruneWarnings); | 
 |   } | 
 |  | 
 |   // Conversion of a floating-point value to a non-bool integer where the | 
 |   // integral part cannot be represented by the integer type is undefined. | 
 |   if (!IsBool && Result == llvm::APFloat::opInvalidOp) | 
 |     return DiagnoseImpCast( | 
 |         S, E, T, CContext, | 
 |         IsLiteral ? diag::warn_impcast_literal_float_to_integer_out_of_range | 
 |                   : diag::warn_impcast_float_to_integer_out_of_range, | 
 |         PruneWarnings); | 
 |  | 
 |   unsigned DiagID = 0; | 
 |   if (IsLiteral) { | 
 |     // Warn on floating point literal to integer. | 
 |     DiagID = diag::warn_impcast_literal_float_to_integer; | 
 |   } else if (IntegerValue == 0) { | 
 |     if (Value.isZero()) {  // Skip -0.0 to 0 conversion. | 
 |       return DiagnoseImpCast(S, E, T, CContext, | 
 |                              diag::warn_impcast_float_integer, PruneWarnings); | 
 |     } | 
 |     // Warn on non-zero to zero conversion. | 
 |     DiagID = diag::warn_impcast_float_to_integer_zero; | 
 |   } else { | 
 |     if (IntegerValue.isUnsigned()) { | 
 |       if (!IntegerValue.isMaxValue()) { | 
 |         return DiagnoseImpCast(S, E, T, CContext, | 
 |                                diag::warn_impcast_float_integer, PruneWarnings); | 
 |       } | 
 |     } else {  // IntegerValue.isSigned() | 
 |       if (!IntegerValue.isMaxSignedValue() && | 
 |           !IntegerValue.isMinSignedValue()) { | 
 |         return DiagnoseImpCast(S, E, T, CContext, | 
 |                                diag::warn_impcast_float_integer, PruneWarnings); | 
 |       } | 
 |     } | 
 |     // Warn on evaluatable floating point expression to integer conversion. | 
 |     DiagID = diag::warn_impcast_float_to_integer; | 
 |   } | 
 |  | 
 |   SmallString<16> PrettyTargetValue; | 
 |   if (IsBool) | 
 |     PrettyTargetValue = Value.isZero() ? "false" : "true"; | 
 |   else | 
 |     IntegerValue.toString(PrettyTargetValue); | 
 |  | 
 |   if (PruneWarnings) { | 
 |     S.DiagRuntimeBehavior(E->getExprLoc(), E, | 
 |                           S.PDiag(DiagID) | 
 |                               << E->getType() << T.getUnqualifiedType() | 
 |                               << PrettySourceValue << PrettyTargetValue | 
 |                               << E->getSourceRange() << SourceRange(CContext)); | 
 |   } else { | 
 |     S.Diag(E->getExprLoc(), DiagID) | 
 |         << E->getType() << T.getUnqualifiedType() << PrettySourceValue | 
 |         << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext); | 
 |   } | 
 | } | 
 |  | 
 | /// Analyze the given compound assignment for the possible losing of | 
 | /// floating-point precision. | 
 | static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { | 
 |   assert(isa<CompoundAssignOperator>(E) && | 
 |          "Must be compound assignment operation"); | 
 |   // Recurse on the LHS and RHS in here | 
 |   AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); | 
 |   AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); | 
 |  | 
 |   if (E->getLHS()->getType()->isAtomicType()) | 
 |     S.Diag(E->getOperatorLoc(), diag::warn_atomic_implicit_seq_cst); | 
 |  | 
 |   // Now check the outermost expression | 
 |   const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>(); | 
 |   const auto *RBT = cast<CompoundAssignOperator>(E) | 
 |                         ->getComputationResultType() | 
 |                         ->getAs<BuiltinType>(); | 
 |  | 
 |   // The below checks assume source is floating point. | 
 |   if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return; | 
 |  | 
 |   // 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; | 
 |  | 
 |   // 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); | 
 | } | 
 |  | 
 | static std::string PrettyPrintInRange(const llvm::APSInt &Value, | 
 |                                       IntRange Range) { | 
 |   if (!Range.Width) return "0"; | 
 |  | 
 |   llvm::APSInt ValueInRange = Value; | 
 |   ValueInRange.setIsSigned(!Range.NonNegative); | 
 |   ValueInRange = ValueInRange.trunc(Range.Width); | 
 |   return toString(ValueInRange, 10); | 
 | } | 
 |  | 
 | static bool IsImplicitBoolFloatConversion(Sema &S, const Expr *Ex, | 
 |                                           bool ToBool) { | 
 |   if (!isa<ImplicitCastExpr>(Ex)) | 
 |     return false; | 
 |  | 
 |   const Expr *InnerE = Ex->IgnoreParenImpCasts(); | 
 |   const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr(); | 
 |   const Type *Source = | 
 |     S.Context.getCanonicalType(InnerE->getType()).getTypePtr(); | 
 |   if (Target->isDependentType()) | 
 |     return false; | 
 |  | 
 |   const auto *FloatCandidateBT = | 
 |       dyn_cast<BuiltinType>(ToBool ? Source : Target); | 
 |   const Type *BoolCandidateType = ToBool ? Target : Source; | 
 |  | 
 |   return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) && | 
 |           FloatCandidateBT && (FloatCandidateBT->isFloatingPoint())); | 
 | } | 
 |  | 
 | static void CheckImplicitArgumentConversions(Sema &S, const CallExpr *TheCall, | 
 |                                              SourceLocation CC) { | 
 |   for (unsigned I = 0, N = TheCall->getNumArgs(); I < N; ++I) { | 
 |     const Expr *CurrA = TheCall->getArg(I); | 
 |     if (!IsImplicitBoolFloatConversion(S, CurrA, true)) | 
 |       continue; | 
 |  | 
 |     bool IsSwapped = ((I > 0) && IsImplicitBoolFloatConversion( | 
 |                                      S, TheCall->getArg(I - 1), false)); | 
 |     IsSwapped |= ((I < (N - 1)) && IsImplicitBoolFloatConversion( | 
 |                                        S, TheCall->getArg(I + 1), false)); | 
 |     if (IsSwapped) { | 
 |       // Warn on this floating-point to bool conversion. | 
 |       DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(), | 
 |                       CurrA->getType(), CC, | 
 |                       diag::warn_impcast_floating_point_to_bool); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, | 
 |                                    SourceLocation CC) { | 
 |   // Don't warn on functions which have return type nullptr_t. | 
 |   if (isa<CallExpr>(E)) | 
 |     return; | 
 |  | 
 |   // Check for NULL (GNUNull) or nullptr (CXX11_nullptr). | 
 |   const Expr *NewE = E->IgnoreParenImpCasts(); | 
 |   bool IsGNUNullExpr = isa<GNUNullExpr>(NewE); | 
 |   bool HasNullPtrType = NewE->getType()->isNullPtrType(); | 
 |   if (!IsGNUNullExpr && !HasNullPtrType) | 
 |     return; | 
 |  | 
 |   // Return if target type is a safe conversion. | 
 |   if (T->isAnyPointerType() || T->isBlockPointerType() || | 
 |       T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType()) | 
 |     return; | 
 |  | 
 |   if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, | 
 |                         E->getExprLoc())) | 
 |     return; | 
 |  | 
 |   SourceLocation Loc = E->getSourceRange().getBegin(); | 
 |  | 
 |   // Venture through the macro stacks to get to the source of macro arguments. | 
 |   // The new location is a better location than the complete location that was | 
 |   // passed in. | 
 |   Loc = S.SourceMgr.getTopMacroCallerLoc(Loc); | 
 |   CC = S.SourceMgr.getTopMacroCallerLoc(CC); | 
 |  | 
 |   // __null is usually wrapped in a macro.  Go up a macro if that is the case. | 
 |   if (IsGNUNullExpr && Loc.isMacroID()) { | 
 |     StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( | 
 |         Loc, S.SourceMgr, S.getLangOpts()); | 
 |     if (MacroName == "NULL") | 
 |       Loc = S.SourceMgr.getImmediateExpansionRange(Loc).getBegin(); | 
 |   } | 
 |  | 
 |   // Only warn if the null and context location are in the same macro expansion. | 
 |   if (S.SourceMgr.getFileID(Loc) != S.SourceMgr.getFileID(CC)) | 
 |     return; | 
 |  | 
 |   S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) | 
 |       << HasNullPtrType << T << SourceRange(CC) | 
 |       << FixItHint::CreateReplacement(Loc, | 
 |                                       S.getFixItZeroLiteralForType(T, Loc)); | 
 | } | 
 |  | 
 | // Helper function to filter out cases for constant width constant conversion. | 
 | // Don't warn on char array initialization or for non-decimal values. | 
 | static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, | 
 |                                           SourceLocation CC) { | 
 |   // If initializing from a constant, and the constant starts with '0', | 
 |   // then it is a binary, octal, or hexadecimal.  Allow these constants | 
 |   // to fill all the bits, even if there is a sign change. | 
 |   if (auto *IntLit = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) { | 
 |     const char FirstLiteralCharacter = | 
 |         S.getSourceManager().getCharacterData(IntLit->getBeginLoc())[0]; | 
 |     if (FirstLiteralCharacter == '0') | 
 |       return false; | 
 |   } | 
 |  | 
 |   // If the CC location points to a '{', and the type is char, then assume | 
 |   // assume it is an array initialization. | 
 |   if (CC.isValid() && T->isCharType()) { | 
 |     const char FirstContextCharacter = | 
 |         S.getSourceManager().getCharacterData(CC)[0]; | 
 |     if (FirstContextCharacter == '{') | 
 |       return false; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | static const IntegerLiteral *getIntegerLiteral(Expr *E) { | 
 |   const auto *IL = dyn_cast<IntegerLiteral>(E); | 
 |   if (!IL) { | 
 |     if (auto *UO = dyn_cast<UnaryOperator>(E)) { | 
 |       if (UO->getOpcode() == UO_Minus) | 
 |         return dyn_cast<IntegerLiteral>(UO->getSubExpr()); | 
 |     } | 
 |   } | 
 |  | 
 |   return IL; | 
 | } | 
 |  | 
 | static void DiagnoseIntInBoolContext(Sema &S, Expr *E) { | 
 |   E = E->IgnoreParenImpCasts(); | 
 |   SourceLocation ExprLoc = E->getExprLoc(); | 
 |  | 
 |   if (const auto *BO = dyn_cast<BinaryOperator>(E)) { | 
 |     BinaryOperator::Opcode Opc = BO->getOpcode(); | 
 |     Expr::EvalResult Result; | 
 |     // Do not diagnose unsigned shifts. | 
 |     if (Opc == BO_Shl) { | 
 |       const auto *LHS = getIntegerLiteral(BO->getLHS()); | 
 |       const auto *RHS = getIntegerLiteral(BO->getRHS()); | 
 |       if (LHS && LHS->getValue() == 0) | 
 |         S.Diag(ExprLoc, diag::warn_left_shift_always) << 0; | 
 |       else if (!E->isValueDependent() && LHS && RHS && | 
 |                RHS->getValue().isNonNegative() && | 
 |                E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) | 
 |         S.Diag(ExprLoc, diag::warn_left_shift_always) | 
 |             << (Result.Val.getInt() != 0); | 
 |       else if (E->getType()->isSignedIntegerType()) | 
 |         S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) | 
 |             << FixItHint::CreateInsertion(E->getBeginLoc(), "(") | 
 |             << FixItHint::CreateInsertion(S.getLocForEndOfToken(E->getEndLoc()), | 
 |                                           ") != 0"); | 
 |     } | 
 |   } | 
 |  | 
 |   if (const auto *CO = dyn_cast<ConditionalOperator>(E)) { | 
 |     const auto *LHS = getIntegerLiteral(CO->getTrueExpr()); | 
 |     const auto *RHS = getIntegerLiteral(CO->getFalseExpr()); | 
 |     if (!LHS || !RHS) | 
 |       return; | 
 |     if ((LHS->getValue() == 0 || LHS->getValue() == 1) && | 
 |         (RHS->getValue() == 0 || RHS->getValue() == 1)) | 
 |       // Do not diagnose common idioms. | 
 |       return; | 
 |     if (LHS->getValue() != 0 && RHS->getValue() != 0) | 
 |       S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true); | 
 |   } | 
 | } | 
 |  | 
 | static void DiagnoseMixedUnicodeImplicitConversion(Sema &S, const Type *Source, | 
 |                                                    const Type *Target, Expr *E, | 
 |                                                    QualType T, | 
 |                                                    SourceLocation CC) { | 
 |   assert(Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType() && | 
 |          Source != Target); | 
 |   Expr::EvalResult Result; | 
 |   if (E->EvaluateAsInt(Result, S.getASTContext(), Expr::SE_AllowSideEffects, | 
 |                        S.isConstantEvaluatedContext())) { | 
 |     llvm::APSInt Value(32); | 
 |     Value = Result.Val.getInt(); | 
 |     bool IsASCII = Value <= 0x7F; | 
 |     bool IsBMP = Value <= 0xD7FF || (Value >= 0xE000 && Value <= 0xFFFF); | 
 |     bool ConversionPreservesSemantics = | 
 |         IsASCII || (!Source->isChar8Type() && !Target->isChar8Type() && IsBMP); | 
 |  | 
 |     if (!ConversionPreservesSemantics) { | 
 |       auto IsSingleCodeUnitCP = [](const QualType &T, | 
 |                                    const llvm::APSInt &Value) { | 
 |         if (T->isChar8Type()) | 
 |           return llvm::IsSingleCodeUnitUTF8Codepoint(Value.getExtValue()); | 
 |         if (T->isChar16Type()) | 
 |           return llvm::IsSingleCodeUnitUTF16Codepoint(Value.getExtValue()); | 
 |         assert(T->isChar32Type()); | 
 |         return llvm::IsSingleCodeUnitUTF32Codepoint(Value.getExtValue()); | 
 |       }; | 
 |  | 
 |       S.Diag(CC, diag::warn_impcast_unicode_char_type_constant) | 
 |           << E->getType() << T | 
 |           << IsSingleCodeUnitCP(E->getType().getUnqualifiedType(), Value) | 
 |           << FormatUTFCodeUnitAsCodepoint(Value.getExtValue(), E->getType()); | 
 |     } | 
 |   } else { | 
 |     bool LosesPrecision = S.getASTContext().getIntWidth(E->getType()) > | 
 |                           S.getASTContext().getIntWidth(T); | 
 |     DiagnoseImpCast(S, E, T, CC, | 
 |                     LosesPrecision ? diag::warn_impcast_unicode_precision | 
 |                                    : diag::warn_impcast_unicode_char_type); | 
 |   } | 
 | } | 
 |  | 
 | enum CFIUncheckedCalleeChange { | 
 |   None, | 
 |   Adding, | 
 |   Discarding, | 
 | }; | 
 |  | 
 | static CFIUncheckedCalleeChange AdjustingCFIUncheckedCallee(QualType From, | 
 |                                                             QualType To) { | 
 |   QualType MaybePointee = From->getPointeeType(); | 
 |   if (!MaybePointee.isNull() && MaybePointee->getAs<FunctionType>()) | 
 |     From = MaybePointee; | 
 |   MaybePointee = To->getPointeeType(); | 
 |   if (!MaybePointee.isNull() && MaybePointee->getAs<FunctionType>()) | 
 |     To = MaybePointee; | 
 |  | 
 |   if (const auto *FromFn = From->getAs<FunctionType>()) { | 
 |     if (const auto *ToFn = To->getAs<FunctionType>()) { | 
 |       if (FromFn->getCFIUncheckedCalleeAttr() && | 
 |           !ToFn->getCFIUncheckedCalleeAttr()) | 
 |         return Discarding; | 
 |       if (!FromFn->getCFIUncheckedCalleeAttr() && | 
 |           ToFn->getCFIUncheckedCalleeAttr()) | 
 |         return Adding; | 
 |     } | 
 |   } | 
 |   return None; | 
 | } | 
 |  | 
 | bool Sema::DiscardingCFIUncheckedCallee(QualType From, QualType To) const { | 
 |   From = Context.getCanonicalType(From); | 
 |   To = Context.getCanonicalType(To); | 
 |   return ::AdjustingCFIUncheckedCallee(From, To) == Discarding; | 
 | } | 
 |  | 
 | bool Sema::AddingCFIUncheckedCallee(QualType From, QualType To) const { | 
 |   From = Context.getCanonicalType(From); | 
 |   To = Context.getCanonicalType(To); | 
 |   return ::AdjustingCFIUncheckedCallee(From, To) == Adding; | 
 | } | 
 |  | 
 | void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, | 
 |                                    bool *ICContext, bool IsListInit) { | 
 |   if (E->isTypeDependent() || E->isValueDependent()) return; | 
 |  | 
 |   const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr(); | 
 |   const Type *Target = Context.getCanonicalType(T).getTypePtr(); | 
 |   if (Source == Target) return; | 
 |   if (Target->isDependentType()) return; | 
 |  | 
 |   // If the conversion context location is invalid don't complain. We also | 
 |   // don't want to emit a warning if the issue occurs from the expansion of | 
 |   // a system macro. The problem is that 'getSpellingLoc()' is slow, so we | 
 |   // delay this check as long as possible. Once we detect we are in that | 
 |   // scenario, we just return. | 
 |   if (CC.isInvalid()) | 
 |     return; | 
 |  | 
 |   if (Source->isAtomicType()) | 
 |     Diag(E->getExprLoc(), diag::warn_atomic_implicit_seq_cst); | 
 |  | 
 |   // Diagnose implicit casts to bool. | 
 |   if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { | 
 |     if (isa<StringLiteral>(E)) | 
 |       // Warn on string literal to bool.  Checks for string literals in logical | 
 |       // and expressions, for instance, assert(0 && "error here"), are | 
 |       // prevented by a check in AnalyzeImplicitConversions(). | 
 |       return DiagnoseImpCast(*this, E, T, CC, | 
 |                              diag::warn_impcast_string_literal_to_bool); | 
 |     if (isa<ObjCStringLiteral>(E) || isa<ObjCArrayLiteral>(E) || | 
 |         isa<ObjCDictionaryLiteral>(E) || isa<ObjCBoxedExpr>(E)) { | 
 |       // This covers the literal expressions that evaluate to Objective-C | 
 |       // objects. | 
 |       return DiagnoseImpCast(*this, E, T, CC, | 
 |                              diag::warn_impcast_objective_c_literal_to_bool); | 
 |     } | 
 |     if (Source->isPointerType() || Source->canDecayToPointerType()) { | 
 |       // Warn on pointer to bool conversion that is always true. | 
 |       DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false, | 
 |                                    SourceRange(CC)); | 
 |     } | 
 |   } | 
 |  | 
 |   // If the we're converting a constant to an ObjC BOOL on a platform where BOOL | 
 |   // is a typedef for signed char (macOS), then that constant value has to be 1 | 
 |   // or 0. | 
 |   if (ObjC().isSignedCharBool(T) && Source->isIntegralType(Context)) { | 
 |     Expr::EvalResult Result; | 
 |     if (E->EvaluateAsInt(Result, getASTContext(), Expr::SE_AllowSideEffects)) { | 
 |       if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) { | 
 |         ObjC().adornBoolConversionDiagWithTernaryFixit( | 
 |             E, Diag(CC, diag::warn_impcast_constant_value_to_objc_bool) | 
 |                    << toString(Result.Val.getInt(), 10)); | 
 |       } | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   // Check implicit casts from Objective-C collection literals to specialized | 
 |   // collection types, e.g., NSArray<NSString *> *. | 
 |   if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E)) | 
 |     ObjC().checkArrayLiteral(QualType(Target, 0), ArrayLiteral); | 
 |   else if (auto *DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(E)) | 
 |     ObjC().checkDictionaryLiteral(QualType(Target, 0), DictionaryLiteral); | 
 |  | 
 |   // Strip vector types. | 
 |   if (isa<VectorType>(Source)) { | 
 |     if (Target->isSveVLSBuiltinType() && | 
 |         (ARM().areCompatibleSveTypes(QualType(Target, 0), | 
 |                                      QualType(Source, 0)) || | 
 |          ARM().areLaxCompatibleSveTypes(QualType(Target, 0), | 
 |                                         QualType(Source, 0)))) | 
 |       return; | 
 |  | 
 |     if (Target->isRVVVLSBuiltinType() && | 
 |         (Context.areCompatibleRVVTypes(QualType(Target, 0), | 
 |                                        QualType(Source, 0)) || | 
 |          Context.areLaxCompatibleRVVTypes(QualType(Target, 0), | 
 |                                           QualType(Source, 0)))) | 
 |       return; | 
 |  | 
 |     if (!isa<VectorType>(Target)) { | 
 |       if (SourceMgr.isInSystemMacro(CC)) | 
 |         return; | 
 |       return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_vector_scalar); | 
 |     } else if (getLangOpts().HLSL && | 
 |                Target->castAs<VectorType>()->getNumElements() < | 
 |                    Source->castAs<VectorType>()->getNumElements()) { | 
 |       // Diagnose vector truncation but don't return. We may also want to | 
 |       // diagnose an element conversion. | 
 |       DiagnoseImpCast(*this, E, T, CC, | 
 |                       diag::warn_hlsl_impcast_vector_truncation); | 
 |     } | 
 |  | 
 |     // If the vector cast is cast between two vectors of the same size, it is | 
 |     // a bitcast, not a conversion, except under HLSL where it is a conversion. | 
 |     if (!getLangOpts().HLSL && | 
 |         Context.getTypeSize(Source) == Context.getTypeSize(Target)) | 
 |       return; | 
 |  | 
 |     Source = cast<VectorType>(Source)->getElementType().getTypePtr(); | 
 |     Target = cast<VectorType>(Target)->getElementType().getTypePtr(); | 
 |   } | 
 |   if (auto VecTy = dyn_cast<VectorType>(Target)) | 
 |     Target = VecTy->getElementType().getTypePtr(); | 
 |  | 
 |   // Strip complex types. | 
 |   if (isa<ComplexType>(Source)) { | 
 |     if (!isa<ComplexType>(Target)) { | 
 |       if (SourceMgr.isInSystemMacro(CC) || Target->isBooleanType()) | 
 |         return; | 
 |  | 
 |       return DiagnoseImpCast(*this, E, T, CC, | 
 |                              getLangOpts().CPlusPlus | 
 |                                  ? diag::err_impcast_complex_scalar | 
 |                                  : diag::warn_impcast_complex_scalar); | 
 |     } | 
 |  | 
 |     Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); | 
 |     Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); | 
 |   } | 
 |  | 
 |   const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source); | 
 |   const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target); | 
 |  | 
 |   // Strip SVE vector types | 
 |   if (SourceBT && SourceBT->isSveVLSBuiltinType()) { | 
 |     // Need the original target type for vector type checks | 
 |     const Type *OriginalTarget = Context.getCanonicalType(T).getTypePtr(); | 
 |     // Handle conversion from scalable to fixed when msve-vector-bits is | 
 |     // specified | 
 |     if (ARM().areCompatibleSveTypes(QualType(OriginalTarget, 0), | 
 |                                     QualType(Source, 0)) || | 
 |         ARM().areLaxCompatibleSveTypes(QualType(OriginalTarget, 0), | 
 |                                        QualType(Source, 0))) | 
 |       return; | 
 |  | 
 |     // If the vector cast is cast between two vectors of the same size, it is | 
 |     // a bitcast, not a conversion. | 
 |     if (Context.getTypeSize(Source) == Context.getTypeSize(Target)) | 
 |       return; | 
 |  | 
 |     Source = SourceBT->getSveEltType(Context).getTypePtr(); | 
 |   } | 
 |  | 
 |   if (TargetBT && TargetBT->isSveVLSBuiltinType()) | 
 |     Target = TargetBT->getSveEltType(Context).getTypePtr(); | 
 |  | 
 |   // If the source is floating point... | 
 |   if (SourceBT && SourceBT->isFloatingPoint()) { | 
 |     // ...and the target is floating point... | 
 |     if (TargetBT && TargetBT->isFloatingPoint()) { | 
 |       // ...then warn if we're dropping FP rank. | 
 |  | 
 |       int Order = 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; | 
 |         if (E->EvaluateAsRValue(result, Context)) { | 
 |           // Value might be a float, a float vector, or a float complex. | 
 |           if (IsSameFloatAfterCast( | 
 |                   result.Val, | 
 |                   Context.getFloatTypeSemantics(QualType(TargetBT, 0)), | 
 |                   Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) | 
 |             return; | 
 |         } | 
 |  | 
 |         if (SourceMgr.isInSystemMacro(CC)) | 
 |           return; | 
 |  | 
 |         DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_float_precision); | 
 |       } | 
 |       // ... or possibly if we're increasing rank, too | 
 |       else if (Order < 0) { | 
 |         if (SourceMgr.isInSystemMacro(CC)) | 
 |           return; | 
 |  | 
 |         DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_double_promotion); | 
 |       } | 
 |       return; | 
 |     } | 
 |  | 
 |     // If the target is integral, always warn. | 
 |     if (TargetBT && TargetBT->isInteger()) { | 
 |       if (SourceMgr.isInSystemMacro(CC)) | 
 |         return; | 
 |  | 
 |       DiagnoseFloatingImpCast(*this, E, T, CC); | 
 |     } | 
 |  | 
 |     // Detect the case where a call result is converted from floating-point to | 
 |     // to bool, and the final argument to the call is converted from bool, to | 
 |     // discover this typo: | 
 |     // | 
 |     //    bool b = fabs(x < 1.0);  // should be "bool b = fabs(x) < 1.0;" | 
 |     // | 
 |     // FIXME: This is an incredibly special case; is there some more general | 
 |     // way to detect this class of misplaced-parentheses bug? | 
 |     if (Target->isBooleanType() && isa<CallExpr>(E)) { | 
 |       // Check last argument of function call to see if it is an | 
 |       // implicit cast from a type matching the type the result | 
 |       // is being cast to. | 
 |       CallExpr *CEx = cast<CallExpr>(E); | 
 |       if (unsigned NumArgs = CEx->getNumArgs()) { | 
 |         Expr *LastA = CEx->getArg(NumArgs - 1); | 
 |         Expr *InnerE = LastA->IgnoreParenImpCasts(); | 
 |         if (isa<ImplicitCastExpr>(LastA) && | 
 |             InnerE->getType()->isBooleanType()) { | 
 |           // Warn on this floating-point to bool conversion | 
 |           DiagnoseImpCast(*this, E, T, CC, | 
 |                           diag::warn_impcast_floating_point_to_bool); | 
 |         } | 
 |       } | 
 |     } | 
 |     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, Context, Expr::SE_AllowSideEffects, | 
 |                                   isConstantEvaluatedContext())) { | 
 |         llvm::APFixedPoint Value = Result.Val.getFixedPoint(); | 
 |         llvm::APFixedPoint MaxVal = Context.getFixedPointMax(T); | 
 |         llvm::APFixedPoint MinVal = Context.getFixedPointMin(T); | 
 |         if (Value > MaxVal || Value < MinVal) { | 
 |           DiagRuntimeBehavior(E->getExprLoc(), E, | 
 |                               PDiag(diag::warn_impcast_fixed_point_range) | 
 |                                   << Value.toString() << T | 
 |                                   << E->getSourceRange() | 
 |                                   << clang::SourceRange(CC)); | 
 |           return; | 
 |         } | 
 |       } | 
 |     } else if (Target->isIntegerType()) { | 
 |       Expr::EvalResult Result; | 
 |       if (!isConstantEvaluatedContext() && | 
 |           E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects)) { | 
 |         llvm::APFixedPoint FXResult = Result.Val.getFixedPoint(); | 
 |  | 
 |         bool Overflowed; | 
 |         llvm::APSInt IntResult = FXResult.convertToInt( | 
 |             Context.getIntWidth(T), Target->isSignedIntegerOrEnumerationType(), | 
 |             &Overflowed); | 
 |  | 
 |         if (Overflowed) { | 
 |           DiagRuntimeBehavior(E->getExprLoc(), E, | 
 |                               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 (!isConstantEvaluatedContext() && | 
 |           E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) { | 
 |         llvm::APSInt Value = Result.Val.getInt(); | 
 |  | 
 |         bool Overflowed; | 
 |         llvm::APFixedPoint IntResult = llvm::APFixedPoint::getFromIntValue( | 
 |             Value, Context.getFixedPointSemantics(T), &Overflowed); | 
 |  | 
 |         if (Overflowed) { | 
 |           DiagRuntimeBehavior(E->getExprLoc(), E, | 
 |                               PDiag(diag::warn_impcast_fixed_point_range) | 
 |                                   << toString(Value, /*Radix=*/10) << T | 
 |                                   << E->getSourceRange() | 
 |                                   << clang::SourceRange(CC)); | 
 |           return; | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // If we are casting an integer type to a floating point type without | 
 |   // initialization-list syntax, we might lose accuracy if the floating | 
 |   // point type has a narrower significand than the integer type. | 
 |   if (SourceBT && TargetBT && SourceBT->isIntegerType() && | 
 |       TargetBT->isFloatingType() && !IsListInit) { | 
 |     // Determine the number of precision bits in the source integer type. | 
 |     std::optional<IntRange> SourceRange = | 
 |         TryGetExprRange(Context, E, isConstantEvaluatedContext(), | 
 |                         /*Approximate=*/true); | 
 |     if (!SourceRange) | 
 |       return; | 
 |     unsigned int SourcePrecision = SourceRange->Width; | 
 |  | 
 |     // Determine the number of precision bits in the | 
 |     // target floating point type. | 
 |     unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision( | 
 |         Context.getFloatTypeSemantics(QualType(TargetBT, 0))); | 
 |  | 
 |     if (SourcePrecision > 0 && TargetPrecision > 0 && | 
 |         SourcePrecision > TargetPrecision) { | 
 |  | 
 |       if (std::optional<llvm::APSInt> SourceInt = | 
 |               E->getIntegerConstantExpr(Context)) { | 
 |         // If the source integer is a constant, convert it to the target | 
 |         // floating point type. Issue a warning if the value changes | 
 |         // during the whole conversion. | 
 |         llvm::APFloat TargetFloatValue( | 
 |             Context.getFloatTypeSemantics(QualType(TargetBT, 0))); | 
 |         llvm::APFloat::opStatus ConversionStatus = | 
 |             TargetFloatValue.convertFromAPInt( | 
 |                 *SourceInt, SourceBT->isSignedInteger(), | 
 |                 llvm::APFloat::rmNearestTiesToEven); | 
 |  | 
 |         if (ConversionStatus != llvm::APFloat::opOK) { | 
 |           SmallString<32> PrettySourceValue; | 
 |           SourceInt->toString(PrettySourceValue, 10); | 
 |           SmallString<32> PrettyTargetValue; | 
 |           TargetFloatValue.toString(PrettyTargetValue, TargetPrecision); | 
 |  | 
 |           DiagRuntimeBehavior( | 
 |               E->getExprLoc(), E, | 
 |               PDiag(diag::warn_impcast_integer_float_precision_constant) | 
 |                   << PrettySourceValue << PrettyTargetValue << E->getType() << T | 
 |                   << E->getSourceRange() << clang::SourceRange(CC)); | 
 |         } | 
 |       } else { | 
 |         // Otherwise, the implicit conversion may lose precision. | 
 |         DiagnoseImpCast(*this, E, T, CC, | 
 |                         diag::warn_impcast_integer_float_precision); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   DiagnoseNullConversion(*this, E, T, CC); | 
 |  | 
 |   DiscardMisalignedMemberAddress(Target, E); | 
 |  | 
 |   if (Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType()) { | 
 |     DiagnoseMixedUnicodeImplicitConversion(*this, Source, Target, E, T, CC); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (Target->isBooleanType()) | 
 |     DiagnoseIntInBoolContext(*this, E); | 
 |  | 
 |   if (DiscardingCFIUncheckedCallee(QualType(Source, 0), QualType(Target, 0))) { | 
 |     Diag(CC, diag::warn_cast_discards_cfi_unchecked_callee) | 
 |         << QualType(Source, 0) << QualType(Target, 0); | 
 |   } | 
 |  | 
 |   if (!Source->isIntegerType() || !Target->isIntegerType()) | 
 |     return; | 
 |  | 
 |   // TODO: remove this early return once the false positives for constant->bool | 
 |   // in templates, macros, etc, are reduced or removed. | 
 |   if (Target->isSpecificBuiltinType(BuiltinType::Bool)) | 
 |     return; | 
 |  | 
 |   if (ObjC().isSignedCharBool(T) && !Source->isCharType() && | 
 |       !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) { | 
 |     return ObjC().adornBoolConversionDiagWithTernaryFixit( | 
 |         E, Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) | 
 |                << E->getType()); | 
 |   } | 
 |   std::optional<IntRange> LikelySourceRange = TryGetExprRange( | 
 |       Context, E, isConstantEvaluatedContext(), /*Approximate=*/true); | 
 |   if (!LikelySourceRange) | 
 |     return; | 
 |  | 
 |   IntRange SourceTypeRange = | 
 |       IntRange::forTargetOfCanonicalType(Context, Source); | 
 |   IntRange TargetRange = IntRange::forTargetOfCanonicalType(Context, Target); | 
 |  | 
 |   if (LikelySourceRange->Width > TargetRange.Width) { | 
 |     // If the source is a constant, use a default-on diagnostic. | 
 |     // TODO: this should happen for bitfield stores, too. | 
 |     Expr::EvalResult Result; | 
 |     if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects, | 
 |                          isConstantEvaluatedContext())) { | 
 |       llvm::APSInt Value(32); | 
 |       Value = Result.Val.getInt(); | 
 |  | 
 |       if (SourceMgr.isInSystemMacro(CC)) | 
 |         return; | 
 |  | 
 |       std::string PrettySourceValue = toString(Value, 10); | 
 |       std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); | 
 |  | 
 |       DiagRuntimeBehavior(E->getExprLoc(), E, | 
 |                           PDiag(diag::warn_impcast_integer_precision_constant) | 
 |                               << PrettySourceValue << PrettyTargetValue | 
 |                               << E->getType() << T << E->getSourceRange() | 
 |                               << SourceRange(CC)); | 
 |       return; | 
 |     } | 
 |  | 
 |     // People want to build with -Wshorten-64-to-32 and not -Wconversion. | 
 |     if (SourceMgr.isInSystemMacro(CC)) | 
 |       return; | 
 |  | 
 |     if (const auto *UO = dyn_cast<UnaryOperator>(E)) { | 
 |       if (UO->getOpcode() == UO_Minus) | 
 |         return DiagnoseImpCast( | 
 |             *this, E, T, CC, diag::warn_impcast_integer_precision_on_negation); | 
 |     } | 
 |  | 
 |     if (TargetRange.Width == 32 && Context.getIntWidth(E->getType()) == 64) | 
 |       return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_integer_64_32, | 
 |                              /* pruneControlFlow */ true); | 
 |     return DiagnoseImpCast(*this, E, T, CC, | 
 |                            diag::warn_impcast_integer_precision); | 
 |   } | 
 |  | 
 |   if (TargetRange.Width > SourceTypeRange.Width) { | 
 |     if (auto *UO = dyn_cast<UnaryOperator>(E)) | 
 |       if (UO->getOpcode() == UO_Minus) | 
 |         if (Source->isUnsignedIntegerType()) { | 
 |           if (Target->isUnsignedIntegerType()) | 
 |             return DiagnoseImpCast(*this, E, T, CC, | 
 |                                    diag::warn_impcast_high_order_zero_bits); | 
 |           if (Target->isSignedIntegerType()) | 
 |             return DiagnoseImpCast(*this, E, T, CC, | 
 |                                    diag::warn_impcast_nonnegative_result); | 
 |         } | 
 |   } | 
 |  | 
 |   if (TargetRange.Width == LikelySourceRange->Width && | 
 |       !TargetRange.NonNegative && LikelySourceRange->NonNegative && | 
 |       Source->isSignedIntegerType()) { | 
 |     // Warn when doing a signed to signed conversion, warn if the positive | 
 |     // source value is exactly the width of the target type, which will | 
 |     // cause a negative value to be stored. | 
 |  | 
 |     Expr::EvalResult Result; | 
 |     if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects) && | 
 |         !SourceMgr.isInSystemMacro(CC)) { | 
 |       llvm::APSInt Value = Result.Val.getInt(); | 
 |       if (isSameWidthConstantConversion(*this, E, T, CC)) { | 
 |         std::string PrettySourceValue = toString(Value, 10); | 
 |         std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); | 
 |  | 
 |         Diag(E->getExprLoc(), | 
 |              PDiag(diag::warn_impcast_integer_precision_constant) | 
 |                  << PrettySourceValue << PrettyTargetValue << E->getType() << T | 
 |                  << E->getSourceRange() << SourceRange(CC)); | 
 |         return; | 
 |       } | 
 |     } | 
 |  | 
 |     // Fall through for non-constants to give a sign conversion warning. | 
 |   } | 
 |  | 
 |   if ((!isa<EnumType>(Target) || !isa<EnumType>(Source)) && | 
 |       ((TargetRange.NonNegative && !LikelySourceRange->NonNegative) || | 
 |        (!TargetRange.NonNegative && LikelySourceRange->NonNegative && | 
 |         LikelySourceRange->Width == TargetRange.Width))) { | 
 |     if (SourceMgr.isInSystemMacro(CC)) | 
 |       return; | 
 |  | 
 |     if (SourceBT && SourceBT->isInteger() && TargetBT && | 
 |         TargetBT->isInteger() && | 
 |         Source->isSignedIntegerType() == Target->isSignedIntegerType()) { | 
 |       return; | 
 |     } | 
 |  | 
 |     unsigned DiagID = diag::warn_impcast_integer_sign; | 
 |  | 
 |     // Traditionally, gcc has warned about this under -Wsign-compare. | 
 |     // We also want to warn about it in -Wconversion. | 
 |     // So if -Wconversion is off, use a completely identical diagnostic | 
 |     // in the sign-compare group. | 
 |     // The conditional-checking code will | 
 |     if (ICContext) { | 
 |       DiagID = diag::warn_impcast_integer_sign_conditional; | 
 |       *ICContext = true; | 
 |     } | 
 |  | 
 |     DiagnoseImpCast(*this, E, T, CC, DiagID); | 
 |   } | 
 |  | 
 |   // If we're implicitly converting from an integer into an enumeration, that | 
 |   // is valid in C but invalid in C++. | 
 |   QualType SourceType = E->getEnumCoercedType(Context); | 
 |   const BuiltinType *CoercedSourceBT = SourceType->getAs<BuiltinType>(); | 
 |   if (CoercedSourceBT && CoercedSourceBT->isInteger() && isa<EnumType>(Target)) | 
 |     return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_int_to_enum); | 
 |  | 
 |   // Diagnose conversions between different enumeration types. | 
 |   // In C, we pretend that the type of an EnumConstantDecl is its enumeration | 
 |   // type, to give us better diagnostics. | 
 |   Source = Context.getCanonicalType(SourceType).getTypePtr(); | 
 |  | 
 |   if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>()) | 
 |     if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>()) | 
 |       if (SourceEnum->getDecl()->hasNameForLinkage() && | 
 |           TargetEnum->getDecl()->hasNameForLinkage() && | 
 |           SourceEnum != TargetEnum) { | 
 |         if (SourceMgr.isInSystemMacro(CC)) | 
 |           return; | 
 |  | 
 |         return DiagnoseImpCast(*this, E, SourceType, T, CC, | 
 |                                diag::warn_impcast_different_enum_types); | 
 |       } | 
 | } | 
 |  | 
 | static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, | 
 |                                      SourceLocation CC, QualType T); | 
 |  | 
 | static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, | 
 |                                     SourceLocation CC, bool &ICContext) { | 
 |   E = E->IgnoreParenImpCasts(); | 
 |   // Diagnose incomplete type for second or third operand in C. | 
 |   if (!S.getLangOpts().CPlusPlus && E->getType()->isRecordType()) | 
 |     S.RequireCompleteExprType(E, diag::err_incomplete_type); | 
 |  | 
 |   if (auto *CO = dyn_cast<AbstractConditionalOperator>(E)) | 
 |     return CheckConditionalOperator(S, CO, CC, T); | 
 |  | 
 |   AnalyzeImplicitConversions(S, E, CC); | 
 |   if (E->getType() != T) | 
 |     return S.CheckImplicitConversion(E, T, CC, &ICContext); | 
 | } | 
 |  | 
 | static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, | 
 |                                      SourceLocation CC, QualType T) { | 
 |   AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); | 
 |  | 
 |   Expr *TrueExpr = E->getTrueExpr(); | 
 |   if (auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) | 
 |     TrueExpr = BCO->getCommon(); | 
 |  | 
 |   bool Suspicious = false; | 
 |   CheckConditionalOperand(S, TrueExpr, T, CC, Suspicious); | 
 |   CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); | 
 |  | 
 |   if (T->isBooleanType()) | 
 |     DiagnoseIntInBoolContext(S, E); | 
 |  | 
 |   // If -Wconversion would have warned about either of the candidates | 
 |   // for a signedness conversion to the context type... | 
 |   if (!Suspicious) return; | 
 |  | 
 |   // ...but it's currently ignored... | 
 |   if (!S.Diags.isIgnored(diag::warn_impcast_integer_sign_conditional, CC)) | 
 |     return; | 
 |  | 
 |   // ...then check whether it would have warned about either of the | 
 |   // candidates for a signedness conversion to the condition type. | 
 |   if (E->getType() == T) return; | 
 |  | 
 |   Suspicious = false; | 
 |   S.CheckImplicitConversion(TrueExpr->IgnoreParenImpCasts(), E->getType(), CC, | 
 |                             &Suspicious); | 
 |   if (!Suspicious) | 
 |     S.CheckImplicitConversion(E->getFalseExpr()->IgnoreParenImpCasts(), | 
 |                               E->getType(), CC, &Suspicious); | 
 | } | 
 |  | 
 | /// Check conversion of given expression to boolean. | 
 | /// Input argument E is a logical expression. | 
 | static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { | 
 |   // Run the bool-like conversion checks only for C since there bools are | 
 |   // still not used as the return type from "boolean" operators or as the input | 
 |   // type for conditional operators. | 
 |   if (S.getLangOpts().CPlusPlus) | 
 |     return; | 
 |   if (E->IgnoreParenImpCasts()->getType()->isAtomicType()) | 
 |     return; | 
 |   S.CheckImplicitConversion(E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); | 
 | } | 
 |  | 
 | namespace { | 
 | struct AnalyzeImplicitConversionsWorkItem { | 
 |   Expr *E; | 
 |   SourceLocation CC; | 
 |   bool IsListInit; | 
 | }; | 
 | } | 
 |  | 
 | static void CheckCommaOperand( | 
 |     Sema &S, Expr *E, QualType T, SourceLocation CC, | 
 |     bool ExtraCheckForImplicitConversion, | 
 |     llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) { | 
 |   E = E->IgnoreParenImpCasts(); | 
 |   WorkList.push_back({E, CC, false}); | 
 |  | 
 |   if (ExtraCheckForImplicitConversion && E->getType() != T) | 
 |     S.CheckImplicitConversion(E, T, CC); | 
 | } | 
 |  | 
 | /// Data recursive variant of AnalyzeImplicitConversions. Subexpressions | 
 | /// that should be visited are added to WorkList. | 
 | static void AnalyzeImplicitConversions( | 
 |     Sema &S, AnalyzeImplicitConversionsWorkItem Item, | 
 |     llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) { | 
 |   Expr *OrigE = Item.E; | 
 |   SourceLocation CC = Item.CC; | 
 |  | 
 |   QualType T = OrigE->getType(); | 
 |   Expr *E = OrigE->IgnoreParenImpCasts(); | 
 |  | 
 |   // Propagate whether we are in a C++ list initialization expression. | 
 |   // If so, we do not issue warnings for implicit int-float conversion | 
 |   // precision loss, because C++11 narrowing already handles it. | 
 |   // | 
 |   // HLSL's initialization lists are special, so they shouldn't observe the C++ | 
 |   // behavior here. | 
 |   bool IsListInit = | 
 |       Item.IsListInit || (isa<InitListExpr>(OrigE) && | 
 |                           S.getLangOpts().CPlusPlus && !S.getLangOpts().HLSL); | 
 |  | 
 |   if (E->isTypeDependent() || E->isValueDependent()) | 
 |     return; | 
 |  | 
 |   Expr *SourceExpr = E; | 
 |   // Examine, but don't traverse into the source expression of an | 
 |   // OpaqueValueExpr, since it may have multiple parents and we don't want to | 
 |   // emit duplicate diagnostics. Its fine to examine the form or attempt to | 
 |   // evaluate it in the context of checking the specific conversion to T though. | 
 |   if (auto *OVE = dyn_cast<OpaqueValueExpr>(E)) | 
 |     if (auto *Src = OVE->getSourceExpr()) | 
 |       SourceExpr = Src; | 
 |  | 
 |   if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr)) | 
 |     if (UO->getOpcode() == UO_Not && | 
 |         UO->getSubExpr()->isKnownToHaveBooleanValue()) | 
 |       S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool) | 
 |           << OrigE->getSourceRange() << T->isBooleanType() | 
 |           << FixItHint::CreateReplacement(UO->getBeginLoc(), "!"); | 
 |  | 
 |   if (auto *BO = dyn_cast<BinaryOperator>(SourceExpr)) { | 
 |     if ((BO->getOpcode() == BO_And || BO->getOpcode() == BO_Or) && | 
 |         BO->getLHS()->isKnownToHaveBooleanValue() && | 
 |         BO->getRHS()->isKnownToHaveBooleanValue() && | 
 |         BO->getLHS()->HasSideEffects(S.Context) && | 
 |         BO->getRHS()->HasSideEffects(S.Context)) { | 
 |       SourceManager &SM = S.getSourceManager(); | 
 |       const LangOptions &LO = S.getLangOpts(); | 
 |       SourceLocation BLoc = BO->getOperatorLoc(); | 
 |       SourceLocation ELoc = Lexer::getLocForEndOfToken(BLoc, 0, SM, LO); | 
 |       StringRef SR = clang::Lexer::getSourceText( | 
 |           clang::CharSourceRange::getTokenRange(BLoc, ELoc), SM, LO); | 
 |       // To reduce false positives, only issue the diagnostic if the operator | 
 |       // is explicitly spelled as a punctuator. This suppresses the diagnostic | 
 |       // when using 'bitand' or 'bitor' either as keywords in C++ or as macros | 
 |       // in C, along with other macro spellings the user might invent. | 
 |       if (SR.str() == "&" || SR.str() == "|") { | 
 |  | 
 |         S.Diag(BO->getBeginLoc(), diag::warn_bitwise_instead_of_logical) | 
 |             << (BO->getOpcode() == BO_And ? "&" : "|") | 
 |             << OrigE->getSourceRange() | 
 |             << FixItHint::CreateReplacement( | 
 |                    BO->getOperatorLoc(), | 
 |                    (BO->getOpcode() == BO_And ? "&&" : "||")); | 
 |         S.Diag(BO->getBeginLoc(), diag::note_cast_operand_to_int); | 
 |       } | 
 |     } else if (BO->isCommaOp() && !S.getLangOpts().CPlusPlus) { | 
 |       /// Analyze the given comma operator. The basic idea behind the analysis | 
 |       /// is to analyze the left and right operands slightly differently. The | 
 |       /// left operand needs to check whether the operand itself has an implicit | 
 |       /// conversion, but not whether the left operand induces an implicit | 
 |       /// conversion for the entire comma expression itself. This is similar to | 
 |       /// how CheckConditionalOperand behaves; it's as-if the correct operand | 
 |       /// were directly used for the implicit conversion check. | 
 |       CheckCommaOperand(S, BO->getLHS(), T, BO->getOperatorLoc(), | 
 |                         /*ExtraCheckForImplicitConversion=*/false, WorkList); | 
 |       CheckCommaOperand(S, BO->getRHS(), T, BO->getOperatorLoc(), | 
 |                         /*ExtraCheckForImplicitConversion=*/true, WorkList); | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   // For conditional operators, we analyze the arguments as if they | 
 |   // were being fed directly into the output. | 
 |   if (auto *CO = dyn_cast<AbstractConditionalOperator>(SourceExpr)) { | 
 |     CheckConditionalOperator(S, CO, CC, T); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Check implicit argument conversions for function calls. | 
 |   if (const auto *Call = dyn_cast<CallExpr>(SourceExpr)) | 
 |     CheckImplicitArgumentConversions(S, Call, CC); | 
 |  | 
 |   // Go ahead and check any implicit conversions we might have skipped. | 
 |   // The non-canonical typecheck is just an optimization; | 
 |   // CheckImplicitConversion will filter out dead implicit conversions. | 
 |   if (SourceExpr->getType() != T) | 
 |     S.CheckImplicitConversion(SourceExpr, T, CC, nullptr, IsListInit); | 
 |  | 
 |   // Now continue drilling into this expression. | 
 |  | 
 |   if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { | 
 |     // The bound subexpressions in a PseudoObjectExpr are not reachable | 
 |     // as transitive children. | 
 |     // FIXME: Use a more uniform representation for this. | 
 |     for (auto *SE : POE->semantics()) | 
 |       if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE)) | 
 |         WorkList.push_back({OVE->getSourceExpr(), CC, IsListInit}); | 
 |   } | 
 |  | 
 |   // Skip past explicit casts. | 
 |   if (auto *CE = dyn_cast<ExplicitCastExpr>(E)) { | 
 |     E = CE->getSubExpr(); | 
 |     // In the special case of a C++ function-style cast with braces, | 
 |     // CXXFunctionalCastExpr has an InitListExpr as direct child with a single | 
 |     // initializer. This InitListExpr basically belongs to the cast itself, so | 
 |     // we skip it too. Specifically this is needed to silence -Wdouble-promotion | 
 |     if (isa<CXXFunctionalCastExpr>(CE)) { | 
 |       if (auto *InitListE = dyn_cast<InitListExpr>(E)) { | 
 |         if (InitListE->getNumInits() == 1) { | 
 |           E = InitListE->getInit(0); | 
 |         } | 
 |       } | 
 |     } | 
 |     E = E->IgnoreParenImpCasts(); | 
 |     if (!CE->getType()->isVoidType() && E->getType()->isAtomicType()) | 
 |       S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); | 
 |     WorkList.push_back({E, CC, IsListInit}); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (auto *OutArgE = dyn_cast<HLSLOutArgExpr>(E)) { | 
 |     WorkList.push_back({OutArgE->getArgLValue(), CC, IsListInit}); | 
 |     // The base expression is only used to initialize the parameter for | 
 |     // arguments to `inout` parameters, so we only traverse down the base | 
 |     // expression for `inout` cases. | 
 |     if (OutArgE->isInOut()) | 
 |       WorkList.push_back( | 
 |           {OutArgE->getCastedTemporary()->getSourceExpr(), CC, IsListInit}); | 
 |     WorkList.push_back({OutArgE->getWritebackCast(), CC, IsListInit}); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { | 
 |     // Do a somewhat different check with comparison operators. | 
 |     if (BO->isComparisonOp()) | 
 |       return AnalyzeComparison(S, BO); | 
 |  | 
 |     // And with simple assignments. | 
 |     if (BO->getOpcode() == BO_Assign) | 
 |       return AnalyzeAssignment(S, BO); | 
 |     // And with compound assignments. | 
 |     if (BO->isAssignmentOp()) | 
 |       return AnalyzeCompoundAssignment(S, BO); | 
 |   } | 
 |  | 
 |   // These break the otherwise-useful invariant below.  Fortunately, | 
 |   // we don't really need to recurse into them, because any internal | 
 |   // expressions should have been analyzed already when they were | 
 |   // built into statements. | 
 |   if (isa<StmtExpr>(E)) return; | 
 |  | 
 |   // Don't descend into unevaluated contexts. | 
 |   if (isa<UnaryExprOrTypeTraitExpr>(E)) return; | 
 |  | 
 |   // Now just recurse over the expression's children. | 
 |   CC = E->getExprLoc(); | 
 |   BinaryOperator *BO = dyn_cast<BinaryOperator>(E); | 
 |   bool IsLogicalAndOperator = BO && BO->getOpcode() == BO_LAnd; | 
 |   for (Stmt *SubStmt : E->children()) { | 
 |     Expr *ChildExpr = dyn_cast_or_null<Expr>(SubStmt); | 
 |     if (!ChildExpr) | 
 |       continue; | 
 |  | 
 |     if (auto *CSE = dyn_cast<CoroutineSuspendExpr>(E)) | 
 |       if (ChildExpr == CSE->getOperand()) | 
 |         // Do not recurse over a CoroutineSuspendExpr's operand. | 
 |         // The operand is also a subexpression of getCommonExpr(), and | 
 |         // recursing into it directly would produce duplicate diagnostics. | 
 |         continue; | 
 |  | 
 |     if (IsLogicalAndOperator && | 
 |         isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts())) | 
 |       // Ignore checking string literals that are in logical and operators. | 
 |       // This is a common pattern for asserts. | 
 |       continue; | 
 |     WorkList.push_back({ChildExpr, CC, IsListInit}); | 
 |   } | 
 |  | 
 |   if (BO && BO->isLogicalOp()) { | 
 |     Expr *SubExpr = BO->getLHS()->IgnoreParenImpCasts(); | 
 |     if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr)) | 
 |       ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); | 
 |  | 
 |     SubExpr = BO->getRHS()->IgnoreParenImpCasts(); | 
 |     if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr)) | 
 |       ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); | 
 |   } | 
 |  | 
 |   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) { | 
 |     if (U->getOpcode() == UO_LNot) { | 
 |       ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); | 
 |     } else if (U->getOpcode() != UO_AddrOf) { | 
 |       if (U->getSubExpr()->getType()->isAtomicType()) | 
 |         S.Diag(U->getSubExpr()->getBeginLoc(), | 
 |                diag::warn_atomic_implicit_seq_cst); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// AnalyzeImplicitConversions - Find and report any interesting | 
 | /// implicit conversions in the given expression.  There are a couple | 
 | /// of competing diagnostics here, -Wconversion and -Wsign-compare. | 
 | static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, | 
 |                                        bool IsListInit/*= false*/) { | 
 |   llvm::SmallVector<AnalyzeImplicitConversionsWorkItem, 16> WorkList; | 
 |   WorkList.push_back({OrigE, CC, IsListInit}); | 
 |   while (!WorkList.empty()) | 
 |     AnalyzeImplicitConversions(S, WorkList.pop_back_val(), WorkList); | 
 | } | 
 |  | 
 | // Helper function for Sema::DiagnoseAlwaysNonNullPointer. | 
 | // Returns true when emitting a warning about taking the address of a reference. | 
 | static bool CheckForReference(Sema &SemaRef, const Expr *E, | 
 |                               const PartialDiagnostic &PD) { | 
 |   E = E->IgnoreParenImpCasts(); | 
 |  | 
 |   const FunctionDecl *FD = nullptr; | 
 |  | 
 |   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { | 
 |     if (!DRE->getDecl()->getType()->isReferenceType()) | 
 |       return false; | 
 |   } else if (const MemberExpr *M = dyn_cast<MemberExpr>(E)) { | 
 |     if (!M->getMemberDecl()->getType()->isReferenceType()) | 
 |       return false; | 
 |   } else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) { | 
 |     if (!Call->getCallReturnType(SemaRef.Context)->isReferenceType()) | 
 |       return false; | 
 |     FD = Call->getDirectCallee(); | 
 |   } else { | 
 |     return false; | 
 |   } | 
 |  | 
 |   SemaRef.Diag(E->getExprLoc(), PD); | 
 |  | 
 |   // If possible, point to location of function. | 
 |   if (FD) { | 
 |     SemaRef.Diag(FD->getLocation(), diag::note_reference_is_return_value) << FD; | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | // Returns true if the SourceLocation is expanded from any macro body. | 
 | // Returns false if the SourceLocation is invalid, is from not in a macro | 
 | // expansion, or is from expanded from a top-level macro argument. | 
 | static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { | 
 |   if (Loc.isInvalid()) | 
 |     return false; | 
 |  | 
 |   while (Loc.isMacroID()) { | 
 |     if (SM.isMacroBodyExpansion(Loc)) | 
 |       return true; | 
 |     Loc = SM.getImmediateMacroCallerLoc(Loc); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, | 
 |                                         Expr::NullPointerConstantKind NullKind, | 
 |                                         bool IsEqual, SourceRange Range) { | 
 |   if (!E) | 
 |     return; | 
 |  | 
 |   // Don't warn inside macros. | 
 |   if (E->getExprLoc().isMacroID()) { | 
 |     const SourceManager &SM = getSourceManager(); | 
 |     if (IsInAnyMacroBody(SM, E->getExprLoc()) || | 
 |         IsInAnyMacroBody(SM, Range.getBegin())) | 
 |       return; | 
 |   } | 
 |   E = E->IgnoreImpCasts(); | 
 |  | 
 |   const bool IsCompare = NullKind != Expr::NPCK_NotNull; | 
 |  | 
 |   if (isa<CXXThisExpr>(E)) { | 
 |     unsigned DiagID = IsCompare ? diag::warn_this_null_compare | 
 |                                 : diag::warn_this_bool_conversion; | 
 |     Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual; | 
 |     return; | 
 |   } | 
 |  | 
 |   bool IsAddressOf = false; | 
 |  | 
 |   if (auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) { | 
 |     if (UO->getOpcode() != UO_AddrOf) | 
 |       return; | 
 |     IsAddressOf = true; | 
 |     E = UO->getSubExpr(); | 
 |   } | 
 |  | 
 |   if (IsAddressOf) { | 
 |     unsigned DiagID = IsCompare | 
 |                           ? diag::warn_address_of_reference_null_compare | 
 |                           : diag::warn_address_of_reference_bool_conversion; | 
 |     PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range | 
 |                                          << IsEqual; | 
 |     if (CheckForReference(*this, E, PD)) { | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) { | 
 |     bool IsParam = isa<NonNullAttr>(NonnullAttr); | 
 |     std::string Str; | 
 |     llvm::raw_string_ostream S(Str); | 
 |     E->printPretty(S, nullptr, getPrintingPolicy()); | 
 |     unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare | 
 |                                 : diag::warn_cast_nonnull_to_bool; | 
 |     Diag(E->getExprLoc(), DiagID) << IsParam << S.str() | 
 |       << E->getSourceRange() << Range << IsEqual; | 
 |     Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam; | 
 |   }; | 
 |  | 
 |   // If we have a CallExpr that is tagged with returns_nonnull, we can complain. | 
 |   if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) { | 
 |     if (auto *Callee = Call->getDirectCallee()) { | 
 |       if (const Attr *A = Callee->getAttr<ReturnsNonNullAttr>()) { | 
 |         ComplainAboutNonnullParamOrCall(A); | 
 |         return; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Complain if we are converting a lambda expression to a boolean value | 
 |   // outside of instantiation. | 
 |   if (!inTemplateInstantiation()) { | 
 |     if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) { | 
 |       if (const auto *MRecordDecl = MCallExpr->getRecordDecl(); | 
 |           MRecordDecl && MRecordDecl->isLambda()) { | 
 |         Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool) | 
 |             << /*LambdaPointerConversionOperatorType=*/3 | 
 |             << MRecordDecl->getSourceRange() << Range << IsEqual; | 
 |         return; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Expect to find a single Decl.  Skip anything more complicated. | 
 |   ValueDecl *D = nullptr; | 
 |   if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) { | 
 |     D = R->getDecl(); | 
 |   } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) { | 
 |     D = M->getMemberDecl(); | 
 |   } | 
 |  | 
 |   // Weak Decls can be null. | 
 |   if (!D || D->isWeak()) | 
 |     return; | 
 |  | 
 |   // Check for parameter decl with nonnull attribute | 
 |   if (const auto* PV = dyn_cast<ParmVarDecl>(D)) { | 
 |     if (getCurFunction() && | 
 |         !getCurFunction()->ModifiedNonNullParams.count(PV)) { | 
 |       if (const Attr *A = PV->getAttr<NonNullAttr>()) { | 
 |         ComplainAboutNonnullParamOrCall(A); | 
 |         return; | 
 |       } | 
 |  | 
 |       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); | 
 |  | 
 |         for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) { | 
 |           if (!NonNull->args_size()) { | 
 |               ComplainAboutNonnullParamOrCall(NonNull); | 
 |               return; | 
 |           } | 
 |  | 
 |           for (const ParamIdx &ArgNo : NonNull->args()) { | 
 |             if (ArgNo.getASTIndex() == ParamNo) { | 
 |               ComplainAboutNonnullParamOrCall(NonNull); | 
 |               return; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   QualType T = D->getType(); | 
 |   const bool IsArray = T->isArrayType(); | 
 |   const bool IsFunction = T->isFunctionType(); | 
 |  | 
 |   // Address of function is used to silence the function warning. | 
 |   if (IsAddressOf && IsFunction) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Found nothing. | 
 |   if (!IsAddressOf && !IsFunction && !IsArray) | 
 |     return; | 
 |  | 
 |   // Pretty print the expression for the diagnostic. | 
 |   std::string Str; | 
 |   llvm::raw_string_ostream S(Str); | 
 |   E->printPretty(S, nullptr, getPrintingPolicy()); | 
 |  | 
 |   unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare | 
 |                               : diag::warn_impcast_pointer_to_bool; | 
 |   enum { | 
 |     AddressOf, | 
 |     FunctionPointer, | 
 |     ArrayPointer | 
 |   } DiagType; | 
 |   if (IsAddressOf) | 
 |     DiagType = AddressOf; | 
 |   else if (IsFunction) | 
 |     DiagType = FunctionPointer; | 
 |   else if (IsArray) | 
 |     DiagType = ArrayPointer; | 
 |   else | 
 |     llvm_unreachable("Could not determine diagnostic."); | 
 |   Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange() | 
 |                                 << Range << IsEqual; | 
 |  | 
 |   if (!IsFunction) | 
 |     return; | 
 |  | 
 |   // Suggest '&' to silence the function warning. | 
 |   Diag(E->getExprLoc(), diag::note_function_warning_silence) | 
 |       << FixItHint::CreateInsertion(E->getBeginLoc(), "&"); | 
 |  | 
 |   // Check to see if '()' fixit should be emitted. | 
 |   QualType ReturnType; | 
 |   UnresolvedSet<4> NonTemplateOverloads; | 
 |   tryExprAsCall(*E, ReturnType, NonTemplateOverloads); | 
 |   if (ReturnType.isNull()) | 
 |     return; | 
 |  | 
 |   if (IsCompare) { | 
 |     // There are two cases here.  If there is null constant, the only suggest | 
 |     // for a pointer return type.  If the null is 0, then suggest if the return | 
 |     // type is a pointer or an integer type. | 
 |     if (!ReturnType->isPointerType()) { | 
 |       if (NullKind == Expr::NPCK_ZeroExpression || | 
 |           NullKind == Expr::NPCK_ZeroLiteral) { | 
 |         if (!ReturnType->isIntegerType()) | 
 |           return; | 
 |       } else { | 
 |         return; | 
 |       } | 
 |     } | 
 |   } else { // !IsCompare | 
 |     // For function to bool, only suggest if the function pointer has bool | 
 |     // return type. | 
 |     if (!ReturnType->isSpecificBuiltinType(BuiltinType::Bool)) | 
 |       return; | 
 |   } | 
 |   Diag(E->getExprLoc(), diag::note_function_to_function_call) | 
 |       << FixItHint::CreateInsertion(getLocForEndOfToken(E->getEndLoc()), "()"); | 
 | } | 
 |  | 
 | void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { | 
 |   // Don't diagnose in unevaluated contexts. | 
 |   if (isUnevaluatedContext()) | 
 |     return; | 
 |  | 
 |   // Don't diagnose for value- or type-dependent expressions. | 
 |   if (E->isTypeDependent() || E->isValueDependent()) | 
 |     return; | 
 |  | 
 |   // Check for array bounds violations in cases where the check isn't triggered | 
 |   // elsewhere for other Expr types (like BinaryOperators), e.g. when an | 
 |   // ArraySubscriptExpr is on the RHS of a variable initialization. | 
 |   CheckArrayAccess(E); | 
 |  | 
 |   // This is not the right CC for (e.g.) a variable initialization. | 
 |   AnalyzeImplicitConversions(*this, E, CC); | 
 | } | 
 |  | 
 | void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { | 
 |   ::CheckBoolLikeConversion(*this, E, CC); | 
 | } | 
 |  | 
 | void Sema::CheckForIntOverflow (const Expr *E) { | 
 |   // Use a work list to deal with nested struct initializers. | 
 |   SmallVector<const Expr *, 2> Exprs(1, E); | 
 |  | 
 |   do { | 
 |     const Expr *OriginalE = Exprs.pop_back_val(); | 
 |     const Expr *E = OriginalE->IgnoreParenCasts(); | 
 |  | 
 |     if (isa<BinaryOperator, UnaryOperator>(E)) { | 
 |       E->EvaluateForOverflow(Context); | 
 |       continue; | 
 |     } | 
 |  | 
 |     if (const auto *InitList = dyn_cast<InitListExpr>(OriginalE)) | 
 |       Exprs.append(InitList->inits().begin(), InitList->inits().end()); | 
 |     else if (isa<ObjCBoxedExpr>(OriginalE)) | 
 |       E->EvaluateForOverflow(Context); | 
 |     else if (const auto *Call = dyn_cast<CallExpr>(E)) | 
 |       Exprs.append(Call->arg_begin(), Call->arg_end()); | 
 |     else if (const auto *Message = dyn_cast<ObjCMessageExpr>(E)) | 
 |       Exprs.append(Message->arg_begin(), Message->arg_end()); | 
 |     else if (const auto *Construct = dyn_cast<CXXConstructExpr>(E)) | 
 |       Exprs.append(Construct->arg_begin(), Construct->arg_end()); | 
 |     else if (const auto *Temporary = dyn_cast<CXXBindTemporaryExpr>(E)) | 
 |       Exprs.push_back(Temporary->getSubExpr()); | 
 |     else if (const auto *Array = dyn_cast<ArraySubscriptExpr>(E)) | 
 |       Exprs.push_back(Array->getIdx()); | 
 |     else if (const auto *Compound = dyn_cast<CompoundLiteralExpr>(E)) | 
 |       Exprs.push_back(Compound->getInitializer()); | 
 |     else if (const auto *New = dyn_cast<CXXNewExpr>(E); | 
 |              New && New->isArray()) { | 
 |       if (auto ArraySize = New->getArraySize()) | 
 |         Exprs.push_back(*ArraySize); | 
 |     } else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(OriginalE)) | 
 |       Exprs.push_back(MTE->getSubExpr()); | 
 |   } while (!Exprs.empty()); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | /// Visitor for expressions which looks for unsequenced operations on the | 
 | /// same object. | 
 | class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { | 
 |   using Base = ConstEvaluatedExprVisitor<SequenceChecker>; | 
 |  | 
 |   /// A tree of sequenced regions within an expression. Two regions are | 
 |   /// unsequenced if one is an ancestor or a descendent of the other. When we | 
 |   /// finish processing an expression with sequencing, such as a comma | 
 |   /// expression, we fold its tree nodes into its parent, since they are | 
 |   /// unsequenced with respect to nodes we will visit later. | 
 |   class SequenceTree { | 
 |     struct Value { | 
 |       explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {} | 
 |       unsigned Parent : 31; | 
 |       LLVM_PREFERRED_TYPE(bool) | 
 |       unsigned Merged : 1; | 
 |     }; | 
 |     SmallVector<Value, 8> Values; | 
 |  | 
 |   public: | 
 |     /// A region within an expression which may be sequenced with respect | 
 |     /// to some other region. | 
 |     class Seq { | 
 |       friend class SequenceTree; | 
 |  | 
 |       unsigned Index; | 
 |  | 
 |       explicit Seq(unsigned N) : Index(N) {} | 
 |  | 
 |     public: | 
 |       Seq() : Index(0) {} | 
 |     }; | 
 |  | 
 |     SequenceTree() { Values.push_back(Value(0)); } | 
 |     Seq root() const { return Seq(0); } | 
 |  | 
 |     /// Create a new sequence of operations, which is an unsequenced | 
 |     /// subset of \p Parent. This sequence of operations is sequenced with | 
 |     /// respect to other children of \p Parent. | 
 |     Seq allocate(Seq Parent) { | 
 |       Values.push_back(Value(Parent.Index)); | 
 |       return Seq(Values.size() - 1); | 
 |     } | 
 |  | 
 |     /// Merge a sequence of operations into its parent. | 
 |     void merge(Seq S) { | 
 |       Values[S.Index].Merged = true; | 
 |     } | 
 |  | 
 |     /// Determine whether two operations are unsequenced. This operation | 
 |     /// is asymmetric: \p Cur should be the more recent sequence, and \p Old | 
 |     /// should have been merged into its parent as appropriate. | 
 |     bool isUnsequenced(Seq Cur, Seq Old) { | 
 |       unsigned C = representative(Cur.Index); | 
 |       unsigned Target = representative(Old.Index); | 
 |       while (C >= Target) { | 
 |         if (C == Target) | 
 |           return true; | 
 |         C = Values[C].Parent; | 
 |       } | 
 |       return false; | 
 |     } | 
 |  | 
 |   private: | 
 |     /// Pick a representative for a sequence. | 
 |     unsigned representative(unsigned K) { | 
 |       if (Values[K].Merged) | 
 |         // Perform path compression as we go. | 
 |         return Values[K].Parent = representative(Values[K].Parent); | 
 |       return K; | 
 |     } | 
 |   }; | 
 |  | 
 |   /// An object for which we can track unsequenced uses. | 
 |   using Object = const NamedDecl *; | 
 |  | 
 |   /// Different flavors of object usage which we track. We only track the | 
 |   /// least-sequenced usage of each kind. | 
 |   enum UsageKind { | 
 |     /// A read of an object. Multiple unsequenced reads are OK. | 
 |     UK_Use, | 
 |  | 
 |     /// A modification of an object which is sequenced before the value | 
 |     /// computation of the expression, such as ++n in C++. | 
 |     UK_ModAsValue, | 
 |  | 
 |     /// A modification of an object which is not sequenced before the value | 
 |     /// computation of the expression, such as n++. | 
 |     UK_ModAsSideEffect, | 
 |  | 
 |     UK_Count = UK_ModAsSideEffect + 1 | 
 |   }; | 
 |  | 
 |   /// Bundle together a sequencing region and the expression corresponding | 
 |   /// to a specific usage. One Usage is stored for each usage kind in UsageInfo. | 
 |   struct Usage { | 
 |     const Expr *UsageExpr = nullptr; | 
 |     SequenceTree::Seq Seq; | 
 |  | 
 |     Usage() = default; | 
 |   }; | 
 |  | 
 |   struct UsageInfo { | 
 |     Usage Uses[UK_Count]; | 
 |  | 
 |     /// Have we issued a diagnostic for this object already? | 
 |     bool Diagnosed = false; | 
 |  | 
 |     UsageInfo(); | 
 |   }; | 
 |   using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>; | 
 |  | 
 |   Sema &SemaRef; | 
 |  | 
 |   /// Sequenced regions within the expression. | 
 |   SequenceTree Tree; | 
 |  | 
 |   /// Declaration modifications and references which we have seen. | 
 |   UsageInfoMap UsageMap; | 
 |  | 
 |   /// The region we are currently within. | 
 |   SequenceTree::Seq Region; | 
 |  | 
 |   /// Filled in with declarations which were modified as a side-effect | 
 |   /// (that is, post-increment operations). | 
 |   SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr; | 
 |  | 
 |   /// Expressions to check later. We defer checking these to reduce | 
 |   /// stack usage. | 
 |   SmallVectorImpl<const Expr *> &WorkList; | 
 |  | 
 |   /// RAII object wrapping the visitation of a sequenced subexpression of an | 
 |   /// expression. At the end of this process, the side-effects of the evaluation | 
 |   /// become sequenced with respect to the value computation of the result, so | 
 |   /// we downgrade any UK_ModAsSideEffect within the evaluation to | 
 |   /// UK_ModAsValue. | 
 |   struct SequencedSubexpression { | 
 |     SequencedSubexpression(SequenceChecker &Self) | 
 |       : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) { | 
 |       Self.ModAsSideEffect = &ModAsSideEffect; | 
 |     } | 
 |  | 
 |     ~SequencedSubexpression() { | 
 |       for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) { | 
 |         // Add a new usage with usage kind UK_ModAsValue, and then restore | 
 |         // the previous usage with UK_ModAsSideEffect (thus clearing it if | 
 |         // the previous one was empty). | 
 |         UsageInfo &UI = Self.UsageMap[M.first]; | 
 |         auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect]; | 
 |         Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue); | 
 |         SideEffectUsage = M.second; | 
 |       } | 
 |       Self.ModAsSideEffect = OldModAsSideEffect; | 
 |     } | 
 |  | 
 |     SequenceChecker &Self; | 
 |     SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect; | 
 |     SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect; | 
 |   }; | 
 |  | 
 |   /// RAII object wrapping the visitation of a subexpression which we might | 
 |   /// choose to evaluate as a constant. If any subexpression is evaluated and | 
 |   /// found to be non-constant, this allows us to suppress the evaluation of | 
 |   /// the outer expression. | 
 |   class EvaluationTracker { | 
 |   public: | 
 |     EvaluationTracker(SequenceChecker &Self) | 
 |         : Self(Self), Prev(Self.EvalTracker) { | 
 |       Self.EvalTracker = this; | 
 |     } | 
 |  | 
 |     ~EvaluationTracker() { | 
 |       Self.EvalTracker = Prev; | 
 |       if (Prev) | 
 |         Prev->EvalOK &= EvalOK; | 
 |     } | 
 |  | 
 |     bool evaluate(const Expr *E, bool &Result) { | 
 |       if (!EvalOK || E->isValueDependent()) | 
 |         return false; | 
 |       EvalOK = E->EvaluateAsBooleanCondition( | 
 |           Result, Self.SemaRef.Context, | 
 |           Self.SemaRef.isConstantEvaluatedContext()); | 
 |       return EvalOK; | 
 |     } | 
 |  | 
 |   private: | 
 |     SequenceChecker &Self; | 
 |     EvaluationTracker *Prev; | 
 |     bool EvalOK = true; | 
 |   } *EvalTracker = nullptr; | 
 |  | 
 |   /// Find the object which is produced by the specified expression, | 
 |   /// if any. | 
 |   Object getObject(const Expr *E, bool Mod) const { | 
 |     E = E->IgnoreParenCasts(); | 
 |     if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { | 
 |       if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec)) | 
 |         return getObject(UO->getSubExpr(), Mod); | 
 |     } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { | 
 |       if (BO->getOpcode() == BO_Comma) | 
 |         return getObject(BO->getRHS(), Mod); | 
 |       if (Mod && BO->isAssignmentOp()) | 
 |         return getObject(BO->getLHS(), Mod); | 
 |     } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { | 
 |       // FIXME: Check for more interesting cases, like "x.n = ++x.n". | 
 |       if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts())) | 
 |         return ME->getMemberDecl(); | 
 |     } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) | 
 |       // FIXME: If this is a reference, map through to its value. | 
 |       return DRE->getDecl(); | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   /// Note that an object \p O was modified or used by an expression | 
 |   /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for | 
 |   /// the object \p O as obtained via the \p UsageMap. | 
 |   void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) { | 
 |     // Get the old usage for the given object and usage kind. | 
 |     Usage &U = UI.Uses[UK]; | 
 |     if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) { | 
 |       // If we have a modification as side effect and are in a sequenced | 
 |       // subexpression, save the old Usage so that we can restore it later | 
 |       // in SequencedSubexpression::~SequencedSubexpression. | 
 |       if (UK == UK_ModAsSideEffect && ModAsSideEffect) | 
 |         ModAsSideEffect->push_back(std::make_pair(O, U)); | 
 |       // Then record the new usage with the current sequencing region. | 
 |       U.UsageExpr = UsageExpr; | 
 |       U.Seq = Region; | 
 |     } | 
 |   } | 
 |  | 
 |   /// Check whether a modification or use of an object \p O in an expression | 
 |   /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is | 
 |   /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap. | 
 |   /// \p IsModMod is true when we are checking for a mod-mod unsequenced | 
 |   /// usage and false we are checking for a mod-use unsequenced usage. | 
 |   void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, | 
 |                   UsageKind OtherKind, bool IsModMod) { | 
 |     if (UI.Diagnosed) | 
 |       return; | 
 |  | 
 |     const Usage &U = UI.Uses[OtherKind]; | 
 |     if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) | 
 |       return; | 
 |  | 
 |     const Expr *Mod = U.UsageExpr; | 
 |     const Expr *ModOrUse = UsageExpr; | 
 |     if (OtherKind == UK_Use) | 
 |       std::swap(Mod, ModOrUse); | 
 |  | 
 |     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; | 
 |   } | 
 |  | 
 |   // A note on note{Pre, Post}{Use, Mod}: | 
 |   // | 
 |   // (It helps to follow the algorithm with an expression such as | 
 |   //  "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced | 
 |   //  operations before C++17 and both are well-defined in C++17). | 
 |   // | 
 |   // When visiting a node which uses/modify an object we first call notePreUse | 
 |   // or notePreMod before visiting its sub-expression(s). At this point the | 
 |   // children of the current node have not yet been visited and so the eventual | 
 |   // uses/modifications resulting from the children of the current node have not | 
 |   // been recorded yet. | 
 |   // | 
 |   // We then visit the children of the current node. After that notePostUse or | 
 |   // notePostMod is called. These will 1) detect an unsequenced modification | 
 |   // as side effect (as in "k++ + k") and 2) add a new usage with the | 
 |   // appropriate usage kind. | 
 |   // | 
 |   // We also have to be careful that some operation sequences modification as | 
 |   // side effect as well (for example: || or ,). To account for this we wrap | 
 |   // the visitation of such a sub-expression (for example: the LHS of || or ,) | 
 |   // with SequencedSubexpression. SequencedSubexpression is an RAII object | 
 |   // which record usages which are modifications as side effect, and then | 
 |   // downgrade them (or more accurately restore the previous usage which was a | 
 |   // modification as side effect) when exiting the scope of the sequenced | 
 |   // subexpression. | 
 |  | 
 |   void notePreUse(Object O, const Expr *UseExpr) { | 
 |     UsageInfo &UI = UsageMap[O]; | 
 |     // Uses conflict with other modifications. | 
 |     checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false); | 
 |   } | 
 |  | 
 |   void notePostUse(Object O, const Expr *UseExpr) { | 
 |     UsageInfo &UI = UsageMap[O]; | 
 |     checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, | 
 |                /*IsModMod=*/false); | 
 |     addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use); | 
 |   } | 
 |  | 
 |   void notePreMod(Object O, const Expr *ModExpr) { | 
 |     UsageInfo &UI = UsageMap[O]; | 
 |     // Modifications conflict with other modifications and with uses. | 
 |     checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true); | 
 |     checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false); | 
 |   } | 
 |  | 
 |   void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) { | 
 |     UsageInfo &UI = UsageMap[O]; | 
 |     checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, | 
 |                /*IsModMod=*/true); | 
 |     addUsage(O, UI, ModExpr, /*UsageKind=*/UK); | 
 |   } | 
 |  | 
 | public: | 
 |   SequenceChecker(Sema &S, const Expr *E, | 
 |                   SmallVectorImpl<const Expr *> &WorkList) | 
 |       : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) { | 
 |     Visit(E); | 
 |     // Silence a -Wunused-private-field since WorkList is now unused. | 
 |     // TODO: Evaluate if it can be used, and if not remove it. | 
 |     (void)this->WorkList; | 
 |   } | 
 |  | 
 |   void VisitStmt(const Stmt *S) { | 
 |     // Skip all statements which aren't expressions for now. | 
 |   } | 
 |  | 
 |   void VisitExpr(const Expr *E) { | 
 |     // By default, just recurse to evaluated subexpressions. | 
 |     Base::VisitStmt(E); | 
 |   } | 
 |  | 
 |   void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *CSE) { | 
 |     for (auto *Sub : CSE->children()) { | 
 |       const Expr *ChildExpr = dyn_cast_or_null<Expr>(Sub); | 
 |       if (!ChildExpr) | 
 |         continue; | 
 |  | 
 |       if (ChildExpr == CSE->getOperand()) | 
 |         // Do not recurse over a CoroutineSuspendExpr's operand. | 
 |         // The operand is also a subexpression of getCommonExpr(), and | 
 |         // recursing into it directly could confuse object management | 
 |         // for the sake of sequence tracking. | 
 |         continue; | 
 |  | 
 |       Visit(Sub); | 
 |     } | 
 |   } | 
 |  | 
 |   void VisitCastExpr(const CastExpr *E) { | 
 |     Object O = Object(); | 
 |     if (E->getCastKind() == CK_LValueToRValue) | 
 |       O = getObject(E->getSubExpr(), false); | 
 |  | 
 |     if (O) | 
 |       notePreUse(O, E); | 
 |     VisitExpr(E); | 
 |     if (O) | 
 |       notePostUse(O, E); | 
 |   } | 
 |  | 
 |   void VisitSequencedExpressions(const Expr *SequencedBefore, | 
 |                                  const Expr *SequencedAfter) { | 
 |     SequenceTree::Seq BeforeRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq AfterRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |     { | 
 |       SequencedSubexpression SeqBefore(*this); | 
 |       Region = BeforeRegion; | 
 |       Visit(SequencedBefore); | 
 |     } | 
 |  | 
 |     Region = AfterRegion; | 
 |     Visit(SequencedAfter); | 
 |  | 
 |     Region = OldRegion; | 
 |  | 
 |     Tree.merge(BeforeRegion); | 
 |     Tree.merge(AfterRegion); | 
 |   } | 
 |  | 
 |   void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) { | 
 |     // C++17 [expr.sub]p1: | 
 |     //   The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The | 
 |     //   expression E1 is sequenced before the expression E2. | 
 |     if (SemaRef.getLangOpts().CPlusPlus17) | 
 |       VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS()); | 
 |     else { | 
 |       Visit(ASE->getLHS()); | 
 |       Visit(ASE->getRHS()); | 
 |     } | 
 |   } | 
 |  | 
 |   void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); } | 
 |   void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); } | 
 |   void VisitBinPtrMem(const BinaryOperator *BO) { | 
 |     // C++17 [expr.mptr.oper]p4: | 
 |     //  Abbreviating pm-expression.*cast-expression as E1.*E2, [...] | 
 |     //  the expression E1 is sequenced before the expression E2. | 
 |     if (SemaRef.getLangOpts().CPlusPlus17) | 
 |       VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); | 
 |     else { | 
 |       Visit(BO->getLHS()); | 
 |       Visit(BO->getRHS()); | 
 |     } | 
 |   } | 
 |  | 
 |   void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); } | 
 |   void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); } | 
 |   void VisitBinShlShr(const BinaryOperator *BO) { | 
 |     // C++17 [expr.shift]p4: | 
 |     //  The expression E1 is sequenced before the expression E2. | 
 |     if (SemaRef.getLangOpts().CPlusPlus17) | 
 |       VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); | 
 |     else { | 
 |       Visit(BO->getLHS()); | 
 |       Visit(BO->getRHS()); | 
 |     } | 
 |   } | 
 |  | 
 |   void VisitBinComma(const BinaryOperator *BO) { | 
 |     // C++11 [expr.comma]p1: | 
 |     //   Every value computation and side effect associated with the left | 
 |     //   expression is sequenced before every value computation and side | 
 |     //   effect associated with the right expression. | 
 |     VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); | 
 |   } | 
 |  | 
 |   void VisitBinAssign(const BinaryOperator *BO) { | 
 |     SequenceTree::Seq RHSRegion; | 
 |     SequenceTree::Seq LHSRegion; | 
 |     if (SemaRef.getLangOpts().CPlusPlus17) { | 
 |       RHSRegion = Tree.allocate(Region); | 
 |       LHSRegion = Tree.allocate(Region); | 
 |     } else { | 
 |       RHSRegion = Region; | 
 |       LHSRegion = Region; | 
 |     } | 
 |     SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |     // C++11 [expr.ass]p1: | 
 |     //  [...] the assignment is sequenced after the value computation | 
 |     //  of the right and left operands, [...] | 
 |     // | 
 |     // so check it before inspecting the operands and update the | 
 |     // map afterwards. | 
 |     Object O = getObject(BO->getLHS(), /*Mod=*/true); | 
 |     if (O) | 
 |       notePreMod(O, BO); | 
 |  | 
 |     if (SemaRef.getLangOpts().CPlusPlus17) { | 
 |       // C++17 [expr.ass]p1: | 
 |       //  [...] The right operand is sequenced before the left operand. [...] | 
 |       { | 
 |         SequencedSubexpression SeqBefore(*this); | 
 |         Region = RHSRegion; | 
 |         Visit(BO->getRHS()); | 
 |       } | 
 |  | 
 |       Region = LHSRegion; | 
 |       Visit(BO->getLHS()); | 
 |  | 
 |       if (O && isa<CompoundAssignOperator>(BO)) | 
 |         notePostUse(O, BO); | 
 |  | 
 |     } else { | 
 |       // C++11 does not specify any sequencing between the LHS and RHS. | 
 |       Region = LHSRegion; | 
 |       Visit(BO->getLHS()); | 
 |  | 
 |       if (O && isa<CompoundAssignOperator>(BO)) | 
 |         notePostUse(O, BO); | 
 |  | 
 |       Region = RHSRegion; | 
 |       Visit(BO->getRHS()); | 
 |     } | 
 |  | 
 |     // C++11 [expr.ass]p1: | 
 |     //  the assignment is sequenced [...] before the value computation of the | 
 |     //  assignment expression. | 
 |     // C11 6.5.16/3 has no such rule. | 
 |     Region = OldRegion; | 
 |     if (O) | 
 |       notePostMod(O, BO, | 
 |                   SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue | 
 |                                                   : UK_ModAsSideEffect); | 
 |     if (SemaRef.getLangOpts().CPlusPlus17) { | 
 |       Tree.merge(RHSRegion); | 
 |       Tree.merge(LHSRegion); | 
 |     } | 
 |   } | 
 |  | 
 |   void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) { | 
 |     VisitBinAssign(CAO); | 
 |   } | 
 |  | 
 |   void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } | 
 |   void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } | 
 |   void VisitUnaryPreIncDec(const UnaryOperator *UO) { | 
 |     Object O = getObject(UO->getSubExpr(), true); | 
 |     if (!O) | 
 |       return VisitExpr(UO); | 
 |  | 
 |     notePreMod(O, UO); | 
 |     Visit(UO->getSubExpr()); | 
 |     // C++11 [expr.pre.incr]p1: | 
 |     //   the expression ++x is equivalent to x+=1 | 
 |     notePostMod(O, UO, | 
 |                 SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue | 
 |                                                 : UK_ModAsSideEffect); | 
 |   } | 
 |  | 
 |   void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } | 
 |   void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } | 
 |   void VisitUnaryPostIncDec(const UnaryOperator *UO) { | 
 |     Object O = getObject(UO->getSubExpr(), true); | 
 |     if (!O) | 
 |       return VisitExpr(UO); | 
 |  | 
 |     notePreMod(O, UO); | 
 |     Visit(UO->getSubExpr()); | 
 |     notePostMod(O, UO, UK_ModAsSideEffect); | 
 |   } | 
 |  | 
 |   void VisitBinLOr(const BinaryOperator *BO) { | 
 |     // C++11 [expr.log.or]p2: | 
 |     //  If the second expression is evaluated, every value computation and | 
 |     //  side effect associated with the first expression is sequenced before | 
 |     //  every value computation and side effect associated with the | 
 |     //  second expression. | 
 |     SequenceTree::Seq LHSRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq RHSRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |     EvaluationTracker Eval(*this); | 
 |     { | 
 |       SequencedSubexpression Sequenced(*this); | 
 |       Region = LHSRegion; | 
 |       Visit(BO->getLHS()); | 
 |     } | 
 |  | 
 |     // C++11 [expr.log.or]p1: | 
 |     //  [...] the second operand is not evaluated if the first operand | 
 |     //  evaluates to true. | 
 |     bool EvalResult = false; | 
 |     bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult); | 
 |     bool ShouldVisitRHS = !EvalOK || !EvalResult; | 
 |     if (ShouldVisitRHS) { | 
 |       Region = RHSRegion; | 
 |       Visit(BO->getRHS()); | 
 |     } | 
 |  | 
 |     Region = OldRegion; | 
 |     Tree.merge(LHSRegion); | 
 |     Tree.merge(RHSRegion); | 
 |   } | 
 |  | 
 |   void VisitBinLAnd(const BinaryOperator *BO) { | 
 |     // C++11 [expr.log.and]p2: | 
 |     //  If the second expression is evaluated, every value computation and | 
 |     //  side effect associated with the first expression is sequenced before | 
 |     //  every value computation and side effect associated with the | 
 |     //  second expression. | 
 |     SequenceTree::Seq LHSRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq RHSRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |     EvaluationTracker Eval(*this); | 
 |     { | 
 |       SequencedSubexpression Sequenced(*this); | 
 |       Region = LHSRegion; | 
 |       Visit(BO->getLHS()); | 
 |     } | 
 |  | 
 |     // C++11 [expr.log.and]p1: | 
 |     //  [...] the second operand is not evaluated if the first operand is false. | 
 |     bool EvalResult = false; | 
 |     bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult); | 
 |     bool ShouldVisitRHS = !EvalOK || EvalResult; | 
 |     if (ShouldVisitRHS) { | 
 |       Region = RHSRegion; | 
 |       Visit(BO->getRHS()); | 
 |     } | 
 |  | 
 |     Region = OldRegion; | 
 |     Tree.merge(LHSRegion); | 
 |     Tree.merge(RHSRegion); | 
 |   } | 
 |  | 
 |   void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) { | 
 |     // C++11 [expr.cond]p1: | 
 |     //  [...] Every value computation and side effect associated with the first | 
 |     //  expression is sequenced before every value computation and side effect | 
 |     //  associated with the second or third expression. | 
 |     SequenceTree::Seq ConditionRegion = Tree.allocate(Region); | 
 |  | 
 |     // No sequencing is specified between the true and false expression. | 
 |     // However since exactly one of both is going to be evaluated we can | 
 |     // consider them to be sequenced. This is needed to avoid warning on | 
 |     // something like "x ? y+= 1 : y += 2;" in the case where we will visit | 
 |     // both the true and false expressions because we can't evaluate x. | 
 |     // This will still allow us to detect an expression like (pre C++17) | 
 |     // "(x ? y += 1 : y += 2) = y". | 
 |     // | 
 |     // We don't wrap the visitation of the true and false expression with | 
 |     // SequencedSubexpression because we don't want to downgrade modifications | 
 |     // as side effect in the true and false expressions after the visition | 
 |     // is done. (for example in the expression "(x ? y++ : y++) + y" we should | 
 |     // not warn between the two "y++", but we should warn between the "y++" | 
 |     // and the "y". | 
 |     SequenceTree::Seq TrueRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq FalseRegion = Tree.allocate(Region); | 
 |     SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |     EvaluationTracker Eval(*this); | 
 |     { | 
 |       SequencedSubexpression Sequenced(*this); | 
 |       Region = ConditionRegion; | 
 |       Visit(CO->getCond()); | 
 |     } | 
 |  | 
 |     // C++11 [expr.cond]p1: | 
 |     // [...] The first expression is contextually converted to bool (Clause 4). | 
 |     // It is evaluated and if it is true, the result of the conditional | 
 |     // expression is the value of the second expression, otherwise that of the | 
 |     // third expression. Only one of the second and third expressions is | 
 |     // evaluated. [...] | 
 |     bool EvalResult = false; | 
 |     bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult); | 
 |     bool ShouldVisitTrueExpr = !EvalOK || EvalResult; | 
 |     bool ShouldVisitFalseExpr = !EvalOK || !EvalResult; | 
 |     if (ShouldVisitTrueExpr) { | 
 |       Region = TrueRegion; | 
 |       Visit(CO->getTrueExpr()); | 
 |     } | 
 |     if (ShouldVisitFalseExpr) { | 
 |       Region = FalseRegion; | 
 |       Visit(CO->getFalseExpr()); | 
 |     } | 
 |  | 
 |     Region = OldRegion; | 
 |     Tree.merge(ConditionRegion); | 
 |     Tree.merge(TrueRegion); | 
 |     Tree.merge(FalseRegion); | 
 |   } | 
 |  | 
 |   void VisitCallExpr(const CallExpr *CE) { | 
 |     // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. | 
 |  | 
 |     if (CE->isUnevaluatedBuiltinCall(Context)) | 
 |       return; | 
 |  | 
 |     // C++11 [intro.execution]p15: | 
 |     //   When calling a function [...], every value computation and side effect | 
 |     //   associated with any argument expression, or with the postfix expression | 
 |     //   designating the called function, is sequenced before execution of every | 
 |     //   expression or statement in the body of the function [and thus before | 
 |     //   the value computation of its result]. | 
 |     SequencedSubexpression Sequenced(*this); | 
 |     SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), [&] { | 
 |       // C++17 [expr.call]p5 | 
 |       //   The postfix-expression is sequenced before each expression in the | 
 |       //   expression-list and any default argument. [...] | 
 |       SequenceTree::Seq CalleeRegion; | 
 |       SequenceTree::Seq OtherRegion; | 
 |       if (SemaRef.getLangOpts().CPlusPlus17) { | 
 |         CalleeRegion = Tree.allocate(Region); | 
 |         OtherRegion = Tree.allocate(Region); | 
 |       } else { | 
 |         CalleeRegion = Region; | 
 |         OtherRegion = Region; | 
 |       } | 
 |       SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |       // Visit the callee expression first. | 
 |       Region = CalleeRegion; | 
 |       if (SemaRef.getLangOpts().CPlusPlus17) { | 
 |         SequencedSubexpression Sequenced(*this); | 
 |         Visit(CE->getCallee()); | 
 |       } else { | 
 |         Visit(CE->getCallee()); | 
 |       } | 
 |  | 
 |       // Then visit the argument expressions. | 
 |       Region = OtherRegion; | 
 |       for (const Expr *Argument : CE->arguments()) | 
 |         Visit(Argument); | 
 |  | 
 |       Region = OldRegion; | 
 |       if (SemaRef.getLangOpts().CPlusPlus17) { | 
 |         Tree.merge(CalleeRegion); | 
 |         Tree.merge(OtherRegion); | 
 |       } | 
 |     }); | 
 |   } | 
 |  | 
 |   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CXXOCE) { | 
 |     // C++17 [over.match.oper]p2: | 
 |     //   [...] the operator notation is first transformed to the equivalent | 
 |     //   function-call notation as summarized in Table 12 (where @ denotes one | 
 |     //   of the operators covered in the specified subclause). However, the | 
 |     //   operands are sequenced in the order prescribed for the built-in | 
 |     //   operator (Clause 8). | 
 |     // | 
 |     // From the above only overloaded binary operators and overloaded call | 
 |     // operators have sequencing rules in C++17 that we need to handle | 
 |     // separately. | 
 |     if (!SemaRef.getLangOpts().CPlusPlus17 || | 
 |         (CXXOCE->getNumArgs() != 2 && CXXOCE->getOperator() != OO_Call)) | 
 |       return VisitCallExpr(CXXOCE); | 
 |  | 
 |     enum { | 
 |       NoSequencing, | 
 |       LHSBeforeRHS, | 
 |       RHSBeforeLHS, | 
 |       LHSBeforeRest | 
 |     } SequencingKind; | 
 |     switch (CXXOCE->getOperator()) { | 
 |     case OO_Equal: | 
 |     case OO_PlusEqual: | 
 |     case OO_MinusEqual: | 
 |     case OO_StarEqual: | 
 |     case OO_SlashEqual: | 
 |     case OO_PercentEqual: | 
 |     case OO_CaretEqual: | 
 |     case OO_AmpEqual: | 
 |     case OO_PipeEqual: | 
 |     case OO_LessLessEqual: | 
 |     case OO_GreaterGreaterEqual: | 
 |       SequencingKind = RHSBeforeLHS; | 
 |       break; | 
 |  | 
 |     case OO_LessLess: | 
 |     case OO_GreaterGreater: | 
 |     case OO_AmpAmp: | 
 |     case OO_PipePipe: | 
 |     case OO_Comma: | 
 |     case OO_ArrowStar: | 
 |     case OO_Subscript: | 
 |       SequencingKind = LHSBeforeRHS; | 
 |       break; | 
 |  | 
 |     case OO_Call: | 
 |       SequencingKind = LHSBeforeRest; | 
 |       break; | 
 |  | 
 |     default: | 
 |       SequencingKind = NoSequencing; | 
 |       break; | 
 |     } | 
 |  | 
 |     if (SequencingKind == NoSequencing) | 
 |       return VisitCallExpr(CXXOCE); | 
 |  | 
 |     // This is a call, so all subexpressions are sequenced before the result. | 
 |     SequencedSubexpression Sequenced(*this); | 
 |  | 
 |     SemaRef.runWithSufficientStackSpace(CXXOCE->getExprLoc(), [&] { | 
 |       assert(SemaRef.getLangOpts().CPlusPlus17 && | 
 |              "Should only get there with C++17 and above!"); | 
 |       assert((CXXOCE->getNumArgs() == 2 || CXXOCE->getOperator() == OO_Call) && | 
 |              "Should only get there with an overloaded binary operator" | 
 |              " or an overloaded call operator!"); | 
 |  | 
 |       if (SequencingKind == LHSBeforeRest) { | 
 |         assert(CXXOCE->getOperator() == OO_Call && | 
 |                "We should only have an overloaded call operator here!"); | 
 |  | 
 |         // This is very similar to VisitCallExpr, except that we only have the | 
 |         // C++17 case. The postfix-expression is the first argument of the | 
 |         // CXXOperatorCallExpr. The expressions in the expression-list, if any, | 
 |         // are in the following arguments. | 
 |         // | 
 |         // Note that we intentionally do not visit the callee expression since | 
 |         // it is just a decayed reference to a function. | 
 |         SequenceTree::Seq PostfixExprRegion = Tree.allocate(Region); | 
 |         SequenceTree::Seq ArgsRegion = Tree.allocate(Region); | 
 |         SequenceTree::Seq OldRegion = Region; | 
 |  | 
 |         assert(CXXOCE->getNumArgs() >= 1 && | 
 |                "An overloaded call operator must have at least one argument" | 
 |                " for the postfix-expression!"); | 
 |         const Expr *PostfixExpr = CXXOCE->getArgs()[0]; | 
 |         llvm::ArrayRef<const Expr *> Args(CXXOCE->getArgs() + 1, | 
 |                                           CXXOCE->getNumArgs() - 1); | 
 |  | 
 |         // Visit the postfix-expression first. | 
 |         { | 
 |           Region = PostfixExprRegion; | 
 |           SequencedSubexpression Sequenced(*this); | 
 |           Visit(PostfixExpr); | 
 |         } | 
 |  | 
 |         // Then visit the argument expressions. | 
 |         Region = ArgsRegion; | 
 |         for (const Expr *Arg : Args) | 
 |           Visit(Arg); | 
 |  | 
 |         Region = OldRegion; | 
 |         Tree.merge(PostfixExprRegion); | 
 |         Tree.merge(ArgsRegion); | 
 |       } else { | 
 |         assert(CXXOCE->getNumArgs() == 2 && | 
 |                "Should only have two arguments here!"); | 
 |         assert((SequencingKind == LHSBeforeRHS || | 
 |                 SequencingKind == RHSBeforeLHS) && | 
 |                "Unexpected sequencing kind!"); | 
 |  | 
 |         // We do not visit the callee expression since it is just a decayed | 
 |         // reference to a function. | 
 |         const Expr *E1 = CXXOCE->getArg(0); | 
 |         const Expr *E2 = CXXOCE->getArg(1); | 
 |         if (SequencingKind == RHSBeforeLHS) | 
 |           std::swap(E1, E2); | 
 |  | 
 |         return VisitSequencedExpressions(E1, E2); | 
 |       } | 
 |     }); | 
 |   } | 
 |  | 
 |   void VisitCXXConstructExpr(const CXXConstructExpr *CCE) { | 
 |     // This is a call, so all subexpressions are sequenced before the result. | 
 |     SequencedSubexpression Sequenced(*this); | 
 |  | 
 |     if (!CCE->isListInitialization()) | 
 |       return VisitExpr(CCE); | 
 |  | 
 |     // In C++11, list initializations are sequenced. | 
 |     SequenceExpressionsInOrder( | 
 |         llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs())); | 
 |   } | 
 |  | 
 |   void VisitInitListExpr(const InitListExpr *ILE) { | 
 |     if (!SemaRef.getLangOpts().CPlusPlus11) | 
 |       return VisitExpr(ILE); | 
 |  | 
 |     // In C++11, list initializations are sequenced. | 
 |     SequenceExpressionsInOrder(ILE->inits()); | 
 |   } | 
 |  | 
 |   void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) { | 
 |     // C++20 parenthesized list initializations are sequenced. See C++20 | 
 |     // [decl.init.general]p16.5 and [decl.init.general]p16.6.2.2. | 
 |     SequenceExpressionsInOrder(PLIE->getInitExprs()); | 
 |   } | 
 |  | 
 | private: | 
 |   void SequenceExpressionsInOrder(ArrayRef<const Expr *> ExpressionList) { | 
 |     SmallVector<SequenceTree::Seq, 32> Elts; | 
 |     SequenceTree::Seq Parent = Region; | 
 |     for (const Expr *E : ExpressionList) { | 
 |       if (!E) | 
 |         continue; | 
 |       Region = Tree.allocate(Parent); | 
 |       Elts.push_back(Region); | 
 |       Visit(E); | 
 |     } | 
 |  | 
 |     // Forget that the initializers are sequenced. | 
 |     Region = Parent; | 
 |     for (unsigned I = 0; I < Elts.size(); ++I) | 
 |       Tree.merge(Elts[I]); | 
 |   } | 
 | }; | 
 |  | 
 | SequenceChecker::UsageInfo::UsageInfo() = default; | 
 |  | 
 | } // namespace | 
 |  | 
 | void Sema::CheckUnsequencedOperations(const Expr *E) { | 
 |   SmallVector<const Expr *, 8> WorkList; | 
 |   WorkList.push_back(E); | 
 |   while (!WorkList.empty()) { | 
 |     const Expr *Item = WorkList.pop_back_val(); | 
 |     SequenceChecker(*this, Item, WorkList); | 
 |   } | 
 | } | 
 |  | 
 | void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, | 
 |                               bool IsConstexpr) { | 
 |   llvm::SaveAndRestore ConstantContext(isConstantEvaluatedOverride, | 
 |                                        IsConstexpr || isa<ConstantExpr>(E)); | 
 |   CheckImplicitConversions(E, CheckLoc); | 
 |   if (!E->isInstantiationDependent()) | 
 |     CheckUnsequencedOperations(E); | 
 |   if (!IsConstexpr && !E->isValueDependent()) | 
 |     CheckForIntOverflow(E); | 
 | } | 
 |  | 
 | void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, | 
 |                                        FieldDecl *BitField, | 
 |                                        Expr *Init) { | 
 |   (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc); | 
 | } | 
 |  | 
 | static void diagnoseArrayStarInParamType(Sema &S, QualType PType, | 
 |                                          SourceLocation Loc) { | 
 |   if (!PType->isVariablyModifiedType()) | 
 |     return; | 
 |   if (const auto *PointerTy = dyn_cast<PointerType>(PType)) { | 
 |     diagnoseArrayStarInParamType(S, PointerTy->getPointeeType(), Loc); | 
 |     return; | 
 |   } | 
 |   if (const auto *ReferenceTy = dyn_cast<ReferenceType>(PType)) { | 
 |     diagnoseArrayStarInParamType(S, ReferenceTy->getPointeeType(), Loc); | 
 |     return; | 
 |   } | 
 |   if (const auto *ParenTy = dyn_cast<ParenType>(PType)) { | 
 |     diagnoseArrayStarInParamType(S, ParenTy->getInnerType(), Loc); | 
 |     return; | 
 |   } | 
 |  | 
 |   const ArrayType *AT = S.Context.getAsArrayType(PType); | 
 |   if (!AT) | 
 |     return; | 
 |  | 
 |   if (AT->getSizeModifier() != ArraySizeModifier::Star) { | 
 |     diagnoseArrayStarInParamType(S, AT->getElementType(), Loc); | 
 |     return; | 
 |   } | 
 |  | 
 |   S.Diag(Loc, diag::err_array_star_in_function_definition); | 
 | } | 
 |  | 
 | bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, | 
 |                                     bool CheckParameterNames) { | 
 |   bool HasInvalidParm = false; | 
 |   for (ParmVarDecl *Param : Parameters) { | 
 |     assert(Param && "null in a parameter list"); | 
 |     // C99 6.7.5.3p4: the parameters in a parameter type list in a | 
 |     // function declarator that is part of a function definition of | 
 |     // that function shall not have incomplete type. | 
 |     // | 
 |     // C++23 [dcl.fct.def.general]/p2 | 
 |     // The type of a parameter [...] for a function definition | 
 |     // shall not be a (possibly cv-qualified) class type that is incomplete | 
 |     // or abstract within the function body unless the function is deleted. | 
 |     if (!Param->isInvalidDecl() && | 
 |         (RequireCompleteType(Param->getLocation(), Param->getType(), | 
 |                              diag::err_typecheck_decl_incomplete_type) || | 
 |          RequireNonAbstractType(Param->getBeginLoc(), Param->getOriginalType(), | 
 |                                 diag::err_abstract_type_in_decl, | 
 |                                 AbstractParamType))) { | 
 |       Param->setInvalidDecl(); | 
 |       HasInvalidParm = true; | 
 |     } | 
 |  | 
 |     // C99 6.9.1p5: If the declarator includes a parameter type list, the | 
 |     // declaration of each parameter shall include an identifier. | 
 |     if (CheckParameterNames && Param->getIdentifier() == nullptr && | 
 |         !Param->isImplicit() && !getLangOpts().CPlusPlus) { | 
 |       // Diagnose this as an extension in C17 and earlier. | 
 |       if (!getLangOpts().C23) | 
 |         Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c23); | 
 |     } | 
 |  | 
 |     // C99 6.7.5.3p12: | 
 |     //   If the function declarator is not part of a definition of that | 
 |     //   function, parameters may have incomplete type and may use the [*] | 
 |     //   notation in their sequences of declarator specifiers to specify | 
 |     //   variable length array types. | 
 |     QualType PType = Param->getOriginalType(); | 
 |     // FIXME: This diagnostic should point the '[*]' if source-location | 
 |     // information is added for it. | 
 |     diagnoseArrayStarInParamType(*this, PType, Param->getLocation()); | 
 |  | 
 |     // If the parameter is a c++ class type and it has to be destructed in the | 
 |     // callee function, declare the destructor so that it can be called by the | 
 |     // callee function. Do not perform any direct access check on the dtor here. | 
 |     if (!Param->isInvalidDecl()) { | 
 |       if (CXXRecordDecl *ClassDecl = Param->getType()->getAsCXXRecordDecl()) { | 
 |         if (!ClassDecl->isInvalidDecl() && | 
 |             !ClassDecl->hasIrrelevantDestructor() && | 
 |             !ClassDecl->isDependentContext() && | 
 |             ClassDecl->isParamDestroyedInCallee()) { | 
 |           CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); | 
 |           MarkFunctionReferenced(Param->getLocation(), Destructor); | 
 |           DiagnoseUseOfDecl(Destructor, Param->getLocation()); | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     // Parameters with the pass_object_size attribute only need to be marked | 
 |     // constant at function definitions. Because we lack information about | 
 |     // whether we're on a declaration or definition when we're instantiating the | 
 |     // attribute, we need to check for constness here. | 
 |     if (const auto *Attr = Param->getAttr<PassObjectSizeAttr>()) | 
 |       if (!Param->getType().isConstQualified()) | 
 |         Diag(Param->getLocation(), diag::err_attribute_pointers_only) | 
 |             << Attr->getSpelling() << 1; | 
 |  | 
 |     // Check for parameter names shadowing fields from the class. | 
 |     if (LangOpts.CPlusPlus && !Param->isInvalidDecl()) { | 
 |       // The owning context for the parameter should be the function, but we | 
 |       // want to see if this function's declaration context is a record. | 
 |       DeclContext *DC = Param->getDeclContext(); | 
 |       if (DC && DC->isFunctionOrMethod()) { | 
 |         if (auto *RD = dyn_cast<CXXRecordDecl>(DC->getParent())) | 
 |           CheckShadowInheritedFields(Param->getLocation(), Param->getDeclName(), | 
 |                                      RD, /*DeclIsField*/ false); | 
 |       } | 
 |     } | 
 |  | 
 |     if (!Param->isInvalidDecl() && | 
 |         Param->getOriginalType()->isWebAssemblyTableType()) { | 
 |       Param->setInvalidDecl(); | 
 |       HasInvalidParm = true; | 
 |       Diag(Param->getLocation(), diag::err_wasm_table_as_function_parameter); | 
 |     } | 
 |   } | 
 |  | 
 |   return HasInvalidParm; | 
 | } | 
 |  | 
 | std::optional<std::pair< | 
 |     CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr | 
 |                                                                        *E, | 
 |                                                                    ASTContext | 
 |                                                                        &Ctx); | 
 |  | 
 | /// Compute the alignment and offset of the base class object given the | 
 | /// derived-to-base cast expression and the alignment and offset of the derived | 
 | /// class object. | 
 | static std::pair<CharUnits, CharUnits> | 
 | getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType, | 
 |                                    CharUnits BaseAlignment, CharUnits Offset, | 
 |                                    ASTContext &Ctx) { | 
 |   for (auto PathI = CE->path_begin(), PathE = CE->path_end(); PathI != PathE; | 
 |        ++PathI) { | 
 |     const CXXBaseSpecifier *Base = *PathI; | 
 |     const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); | 
 |     if (Base->isVirtual()) { | 
 |       // The complete object may have a lower alignment than the non-virtual | 
 |       // alignment of the base, in which case the base may be misaligned. Choose | 
 |       // the smaller of the non-virtual alignment and BaseAlignment, which is a | 
 |       // conservative lower bound of the complete object alignment. | 
 |       CharUnits NonVirtualAlignment = | 
 |           Ctx.getASTRecordLayout(BaseDecl).getNonVirtualAlignment(); | 
 |       BaseAlignment = std::min(BaseAlignment, NonVirtualAlignment); | 
 |       Offset = CharUnits::Zero(); | 
 |     } else { | 
 |       const ASTRecordLayout &RL = | 
 |           Ctx.getASTRecordLayout(DerivedType->getAsCXXRecordDecl()); | 
 |       Offset += RL.getBaseClassOffset(BaseDecl); | 
 |     } | 
 |     DerivedType = Base->getType(); | 
 |   } | 
 |  | 
 |   return std::make_pair(BaseAlignment, Offset); | 
 | } | 
 |  | 
 | /// Compute the alignment and offset of a binary additive operator. | 
 | static std::optional<std::pair<CharUnits, CharUnits>> | 
 | getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE, | 
 |                                      bool IsSub, ASTContext &Ctx) { | 
 |   QualType PointeeType = PtrE->getType()->getPointeeType(); | 
 |  | 
 |   if (!PointeeType->isConstantSizeType()) | 
 |     return std::nullopt; | 
 |  | 
 |   auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx); | 
 |  | 
 |   if (!P) | 
 |     return std::nullopt; | 
 |  | 
 |   CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType); | 
 |   if (std::optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) { | 
 |     CharUnits Offset = EltSize * IdxRes->getExtValue(); | 
 |     if (IsSub) | 
 |       Offset = -Offset; | 
 |     return std::make_pair(P->first, P->second + Offset); | 
 |   } | 
 |  | 
 |   // If the integer expression isn't a constant expression, compute the lower | 
 |   // bound of the alignment using the alignment and offset of the pointer | 
 |   // expression and the element size. | 
 |   return std::make_pair( | 
 |       P->first.alignmentAtOffset(P->second).alignmentAtOffset(EltSize), | 
 |       CharUnits::Zero()); | 
 | } | 
 |  | 
 | /// This helper function takes an lvalue expression and returns the alignment of | 
 | /// a VarDecl and a constant offset from the VarDecl. | 
 | std::optional<std::pair< | 
 |     CharUnits, | 
 |     CharUnits>> static getBaseAlignmentAndOffsetFromLValue(const Expr *E, | 
 |                                                            ASTContext &Ctx) { | 
 |   E = E->IgnoreParens(); | 
 |   switch (E->getStmtClass()) { | 
 |   default: | 
 |     break; | 
 |   case Stmt::CStyleCastExprClass: | 
 |   case Stmt::CXXStaticCastExprClass: | 
 |   case Stmt::ImplicitCastExprClass: { | 
 |     auto *CE = cast<CastExpr>(E); | 
 |     const Expr *From = CE->getSubExpr(); | 
 |     switch (CE->getCastKind()) { | 
 |     default: | 
 |       break; | 
 |     case CK_NoOp: | 
 |       return getBaseAlignmentAndOffsetFromLValue(From, Ctx); | 
 |     case CK_UncheckedDerivedToBase: | 
 |     case CK_DerivedToBase: { | 
 |       auto P = getBaseAlignmentAndOffsetFromLValue(From, Ctx); | 
 |       if (!P) | 
 |         break; | 
 |       return getDerivedToBaseAlignmentAndOffset(CE, From->getType(), P->first, | 
 |                                                 P->second, Ctx); | 
 |     } | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Stmt::ArraySubscriptExprClass: { | 
 |     auto *ASE = cast<ArraySubscriptExpr>(E); | 
 |     return getAlignmentAndOffsetFromBinAddOrSub(ASE->getBase(), ASE->getIdx(), | 
 |                                                 false, Ctx); | 
 |   } | 
 |   case Stmt::DeclRefExprClass: { | 
 |     if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { | 
 |       // FIXME: If VD is captured by copy or is an escaping __block variable, | 
 |       // use the alignment of VD's type. | 
 |       if (!VD->getType()->isReferenceType()) { | 
 |         // Dependent alignment cannot be resolved -> bail out. | 
 |         if (VD->hasDependentAlignment()) | 
 |           break; | 
 |         return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero()); | 
 |       } | 
 |       if (VD->hasInit()) | 
 |         return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Stmt::MemberExprClass: { | 
 |     auto *ME = cast<MemberExpr>(E); | 
 |     auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); | 
 |     if (!FD || FD->getType()->isReferenceType() || | 
 |         FD->getParent()->isInvalidDecl()) | 
 |       break; | 
 |     std::optional<std::pair<CharUnits, CharUnits>> P; | 
 |     if (ME->isArrow()) | 
 |       P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx); | 
 |     else | 
 |       P = getBaseAlignmentAndOffsetFromLValue(ME->getBase(), Ctx); | 
 |     if (!P) | 
 |       break; | 
 |     const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent()); | 
 |     uint64_t Offset = Layout.getFieldOffset(FD->getFieldIndex()); | 
 |     return std::make_pair(P->first, | 
 |                           P->second + CharUnits::fromQuantity(Offset)); | 
 |   } | 
 |   case Stmt::UnaryOperatorClass: { | 
 |     auto *UO = cast<UnaryOperator>(E); | 
 |     switch (UO->getOpcode()) { | 
 |     default: | 
 |       break; | 
 |     case UO_Deref: | 
 |       return getBaseAlignmentAndOffsetFromPtr(UO->getSubExpr(), Ctx); | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Stmt::BinaryOperatorClass: { | 
 |     auto *BO = cast<BinaryOperator>(E); | 
 |     auto Opcode = BO->getOpcode(); | 
 |     switch (Opcode) { | 
 |     default: | 
 |       break; | 
 |     case BO_Comma: | 
 |       return getBaseAlignmentAndOffsetFromLValue(BO->getRHS(), Ctx); | 
 |     } | 
 |     break; | 
 |   } | 
 |   } | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | /// This helper function takes a pointer expression and returns the alignment of | 
 | /// a VarDecl and a constant offset from the VarDecl. | 
 | std::optional<std::pair< | 
 |     CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr | 
 |                                                                        *E, | 
 |                                                                    ASTContext | 
 |                                                                        &Ctx) { | 
 |   E = E->IgnoreParens(); | 
 |   switch (E->getStmtClass()) { | 
 |   default: | 
 |     break; | 
 |   case Stmt::CStyleCastExprClass: | 
 |   case Stmt::CXXStaticCastExprClass: | 
 |   case Stmt::ImplicitCastExprClass: { | 
 |     auto *CE = cast<CastExpr>(E); | 
 |     const Expr *From = CE->getSubExpr(); | 
 |     switch (CE->getCastKind()) { | 
 |     default: | 
 |       break; | 
 |     case CK_NoOp: | 
 |       return getBaseAlignmentAndOffsetFromPtr(From, Ctx); | 
 |     case CK_ArrayToPointerDecay: | 
 |       return getBaseAlignmentAndOffsetFromLValue(From, Ctx); | 
 |     case CK_UncheckedDerivedToBase: | 
 |     case CK_DerivedToBase: { | 
 |       auto P = getBaseAlignmentAndOffsetFromPtr(From, Ctx); | 
 |       if (!P) | 
 |         break; | 
 |       return getDerivedToBaseAlignmentAndOffset( | 
 |           CE, From->getType()->getPointeeType(), P->first, P->second, Ctx); | 
 |     } | 
 |     } | 
 |     break; | 
 |   } | 
 |   case Stmt::CXXThisExprClass: { | 
 |     auto *RD = E->getType()->getPointeeType()->getAsCXXRecordDecl(); | 
 |     CharUnits Alignment = Ctx.getASTRecordLayout(RD).getNonVirtualAlignment(); | 
 |     return std::make_pair(Alignment, CharUnits::Zero()); | 
 |   } | 
 |   case Stmt::UnaryOperatorClass: { | 
 |     auto *UO = cast<UnaryOperator>(E); | 
 |     if (UO->getOpcode() == UO_AddrOf) | 
 |       return getBaseAlignmentAndOffsetFromLValue(UO->getSubExpr(), Ctx); | 
 |     break; | 
 |   } | 
 |   case Stmt::BinaryOperatorClass: { | 
 |     auto *BO = cast<BinaryOperator>(E); | 
 |     auto Opcode = BO->getOpcode(); | 
 |     switch (Opcode) { | 
 |     default: | 
 |       break; | 
 |     case BO_Add: | 
 |     case BO_Sub: { | 
 |       const Expr *LHS = BO->getLHS(), *RHS = BO->getRHS(); | 
 |       if (Opcode == BO_Add && !RHS->getType()->isIntegralOrEnumerationType()) | 
 |         std::swap(LHS, RHS); | 
 |       return getAlignmentAndOffsetFromBinAddOrSub(LHS, RHS, Opcode == BO_Sub, | 
 |                                                   Ctx); | 
 |     } | 
 |     case BO_Comma: | 
 |       return getBaseAlignmentAndOffsetFromPtr(BO->getRHS(), Ctx); | 
 |     } | 
 |     break; | 
 |   } | 
 |   } | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) { | 
 |   // See if we can compute the alignment of a VarDecl and an offset from it. | 
 |   std::optional<std::pair<CharUnits, CharUnits>> P = | 
 |       getBaseAlignmentAndOffsetFromPtr(E, S.Context); | 
 |  | 
 |   if (P) | 
 |     return P->first.alignmentAtOffset(P->second); | 
 |  | 
 |   // If that failed, return the type's alignment. | 
 |   return S.Context.getTypeAlignInChars(E->getType()->getPointeeType()); | 
 | } | 
 |  | 
 | void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { | 
 |   // This is actually a lot of work to potentially be doing on every | 
 |   // cast; don't do it if we're ignoring -Wcast_align (as is the default). | 
 |   if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin())) | 
 |     return; | 
 |  | 
 |   // Ignore dependent types. | 
 |   if (T->isDependentType() || Op->getType()->isDependentType()) | 
 |     return; | 
 |  | 
 |   // Require that the destination be a pointer type. | 
 |   const PointerType *DestPtr = T->getAs<PointerType>(); | 
 |   if (!DestPtr) return; | 
 |  | 
 |   // If the destination has alignment 1, we're done. | 
 |   QualType DestPointee = DestPtr->getPointeeType(); | 
 |   if (DestPointee->isIncompleteType()) return; | 
 |   CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee); | 
 |   if (DestAlign.isOne()) return; | 
 |  | 
 |   // Require that the source be a pointer type. | 
 |   const PointerType *SrcPtr = Op->getType()->getAs<PointerType>(); | 
 |   if (!SrcPtr) return; | 
 |   QualType SrcPointee = SrcPtr->getPointeeType(); | 
 |  | 
 |   // Explicitly allow casts from cv void*.  We already implicitly | 
 |   // allowed casts to cv void*, since they have alignment 1. | 
 |   // Also allow casts involving incomplete types, which implicitly | 
 |   // includes 'void'. | 
 |   if (SrcPointee->isIncompleteType()) return; | 
 |  | 
 |   CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this); | 
 |  | 
 |   if (SrcAlign >= DestAlign) return; | 
 |  | 
 |   Diag(TRange.getBegin(), diag::warn_cast_align) | 
 |     << Op->getType() << T | 
 |     << static_cast<unsigned>(SrcAlign.getQuantity()) | 
 |     << static_cast<unsigned>(DestAlign.getQuantity()) | 
 |     << TRange << Op->getSourceRange(); | 
 | } | 
 |  | 
 | void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, | 
 |                             const ArraySubscriptExpr *ASE, | 
 |                             bool AllowOnePastEnd, bool IndexNegated) { | 
 |   // Already diagnosed by the constant evaluator. | 
 |   if (isConstantEvaluatedContext()) | 
 |     return; | 
 |  | 
 |   IndexExpr = IndexExpr->IgnoreParenImpCasts(); | 
 |   if (IndexExpr->isValueDependent()) | 
 |     return; | 
 |  | 
 |   const Type *EffectiveType = | 
 |       BaseExpr->getType()->getPointeeOrArrayElementType(); | 
 |   BaseExpr = BaseExpr->IgnoreParenCasts(); | 
 |   const ConstantArrayType *ArrayTy = | 
 |       Context.getAsConstantArrayType(BaseExpr->getType()); | 
 |  | 
 |   LangOptions::StrictFlexArraysLevelKind | 
 |     StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); | 
 |  | 
 |   const Type *BaseType = | 
 |       ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr(); | 
 |   bool IsUnboundedArray = | 
 |       BaseType == nullptr || BaseExpr->isFlexibleArrayMemberLike( | 
 |                                  Context, StrictFlexArraysLevel, | 
 |                                  /*IgnoreTemplateOrMacroSubstitution=*/true); | 
 |   if (EffectiveType->isDependentType() || | 
 |       (!IsUnboundedArray && BaseType->isDependentType())) | 
 |     return; | 
 |  | 
 |   Expr::EvalResult Result; | 
 |   if (!IndexExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) | 
 |     return; | 
 |  | 
 |   llvm::APSInt index = Result.Val.getInt(); | 
 |   if (IndexNegated) { | 
 |     index.setIsUnsigned(false); | 
 |     index = -index; | 
 |   } | 
 |  | 
 |   if (IsUnboundedArray) { | 
 |     if (EffectiveType->isFunctionType()) | 
 |       return; | 
 |     if (index.isUnsigned() || !index.isNegative()) { | 
 |       const auto &ASTC = getASTContext(); | 
 |       unsigned AddrBits = ASTC.getTargetInfo().getPointerWidth( | 
 |           EffectiveType->getCanonicalTypeInternal().getAddressSpace()); | 
 |       if (index.getBitWidth() < AddrBits) | 
 |         index = index.zext(AddrBits); | 
 |       std::optional<CharUnits> ElemCharUnits = | 
 |           ASTC.getTypeSizeInCharsIfKnown(EffectiveType); | 
 |       // PR50741 - If EffectiveType has unknown size (e.g., if it's a void | 
 |       // pointer) bounds-checking isn't meaningful. | 
 |       if (!ElemCharUnits || ElemCharUnits->isZero()) | 
 |         return; | 
 |       llvm::APInt ElemBytes(index.getBitWidth(), ElemCharUnits->getQuantity()); | 
 |       // If index has more active bits than address space, we already know | 
 |       // we have a bounds violation to warn about.  Otherwise, compute | 
 |       // address of (index + 1)th element, and warn about bounds violation | 
 |       // only if that address exceeds address space. | 
 |       if (index.getActiveBits() <= AddrBits) { | 
 |         bool Overflow; | 
 |         llvm::APInt Product(index); | 
 |         Product += 1; | 
 |         Product = Product.umul_ov(ElemBytes, Overflow); | 
 |         if (!Overflow && Product.getActiveBits() <= AddrBits) | 
 |           return; | 
 |       } | 
 |  | 
 |       // Need to compute max possible elements in address space, since that | 
 |       // is included in diag message. | 
 |       llvm::APInt MaxElems = llvm::APInt::getMaxValue(AddrBits); | 
 |       MaxElems = MaxElems.zext(std::max(AddrBits + 1, ElemBytes.getBitWidth())); | 
 |       MaxElems += 1; | 
 |       ElemBytes = ElemBytes.zextOrTrunc(MaxElems.getBitWidth()); | 
 |       MaxElems = MaxElems.udiv(ElemBytes); | 
 |  | 
 |       unsigned DiagID = | 
 |           ASE ? diag::warn_array_index_exceeds_max_addressable_bounds | 
 |               : diag::warn_ptr_arith_exceeds_max_addressable_bounds; | 
 |  | 
 |       // Diag message shows element size in bits and in "bytes" (platform- | 
 |       // dependent CharUnits) | 
 |       DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr, | 
 |                           PDiag(DiagID) << index << AddrBits | 
 |                                         << (unsigned)ASTC.toBits(*ElemCharUnits) | 
 |                                         << ElemBytes << MaxElems | 
 |                                         << MaxElems.getZExtValue() | 
 |                                         << IndexExpr->getSourceRange()); | 
 |  | 
 |       const NamedDecl *ND = nullptr; | 
 |       // Try harder to find a NamedDecl to point at in the note. | 
 |       while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr)) | 
 |         BaseExpr = ASE->getBase()->IgnoreParenCasts(); | 
 |       if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) | 
 |         ND = DRE->getDecl(); | 
 |       if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr)) | 
 |         ND = ME->getMemberDecl(); | 
 |  | 
 |       if (ND) | 
 |         DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr, | 
 |                             PDiag(diag::note_array_declared_here) << ND); | 
 |     } | 
 |     return; | 
 |   } | 
 |  | 
 |   if (index.isUnsigned() || !index.isNegative()) { | 
 |     // It is possible that the type of the base expression after | 
 |     // IgnoreParenCasts is incomplete, even though the type of the base | 
 |     // expression before IgnoreParenCasts is complete (see PR39746 for an | 
 |     // example). In this case we have no information about whether the array | 
 |     // access exceeds the array bounds. However we can still diagnose an array | 
 |     // access which precedes the array bounds. | 
 |     if (BaseType->isIncompleteType()) | 
 |       return; | 
 |  | 
 |     llvm::APInt size = ArrayTy->getSize(); | 
 |  | 
 |     if (BaseType != EffectiveType) { | 
 |       // Make sure we're comparing apples to apples when comparing index to | 
 |       // size. | 
 |       uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); | 
 |       uint64_t array_typesize = Context.getTypeSize(BaseType); | 
 |  | 
 |       // Handle ptrarith_typesize being zero, such as when casting to void*. | 
 |       // Use the size in bits (what "getTypeSize()" returns) rather than bytes. | 
 |       if (!ptrarith_typesize) | 
 |         ptrarith_typesize = Context.getCharWidth(); | 
 |  | 
 |       if (ptrarith_typesize != array_typesize) { | 
 |         // There's a cast to a different size type involved. | 
 |         uint64_t ratio = array_typesize / ptrarith_typesize; | 
 |  | 
 |         // TODO: Be smarter about handling cases where array_typesize is not a | 
 |         // multiple of ptrarith_typesize. | 
 |         if (ptrarith_typesize * ratio == array_typesize) | 
 |           size *= llvm::APInt(size.getBitWidth(), ratio); | 
 |       } | 
 |     } | 
 |  | 
 |     if (size.getBitWidth() > index.getBitWidth()) | 
 |       index = index.zext(size.getBitWidth()); | 
 |     else if (size.getBitWidth() < index.getBitWidth()) | 
 |       size = size.zext(index.getBitWidth()); | 
 |  | 
 |     // For array subscripting the index must be less than size, but for pointer | 
 |     // arithmetic also allow the index (offset) to be equal to size since | 
 |     // computing the next address after the end of the array is legal and | 
 |     // commonly done e.g. in C++ iterators and range-based for loops. | 
 |     if (AllowOnePastEnd ? index.ule(size) : index.ult(size)) | 
 |       return; | 
 |  | 
 |     // Suppress the warning if the subscript expression (as identified by the | 
 |     // ']' location) and the index expression are both from macro expansions | 
 |     // within a system header. | 
 |     if (ASE) { | 
 |       SourceLocation RBracketLoc = SourceMgr.getSpellingLoc( | 
 |           ASE->getRBracketLoc()); | 
 |       if (SourceMgr.isInSystemHeader(RBracketLoc)) { | 
 |         SourceLocation IndexLoc = | 
 |             SourceMgr.getSpellingLoc(IndexExpr->getBeginLoc()); | 
 |         if (SourceMgr.isWrittenInSameFile(RBracketLoc, IndexLoc)) | 
 |           return; | 
 |       } | 
 |     } | 
 |  | 
 |     unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds | 
 |                           : diag::warn_ptr_arith_exceeds_bounds; | 
 |     unsigned CastMsg = (!ASE || BaseType == EffectiveType) ? 0 : 1; | 
 |     QualType CastMsgTy = ASE ? ASE->getLHS()->getType() : QualType(); | 
 |  | 
 |     DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr, | 
 |                         PDiag(DiagID) | 
 |                             << index << ArrayTy->desugar() << CastMsg | 
 |                             << CastMsgTy << IndexExpr->getSourceRange()); | 
 |   } else { | 
 |     unsigned DiagID = diag::warn_array_index_precedes_bounds; | 
 |     if (!ASE) { | 
 |       DiagID = diag::warn_ptr_arith_precedes_bounds; | 
 |       if (index.isNegative()) index = -index; | 
 |     } | 
 |  | 
 |     DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr, | 
 |                         PDiag(DiagID) << index << IndexExpr->getSourceRange()); | 
 |   } | 
 |  | 
 |   const NamedDecl *ND = nullptr; | 
 |   // Try harder to find a NamedDecl to point at in the note. | 
 |   while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr)) | 
 |     BaseExpr = ASE->getBase()->IgnoreParenCasts(); | 
 |   if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) | 
 |     ND = DRE->getDecl(); | 
 |   if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr)) | 
 |     ND = ME->getMemberDecl(); | 
 |  | 
 |   if (ND) | 
 |     DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr, | 
 |                         PDiag(diag::note_array_declared_here) << ND); | 
 | } | 
 |  | 
 | void Sema::CheckArrayAccess(const Expr *expr) { | 
 |   int AllowOnePastEnd = 0; | 
 |   while (expr) { | 
 |     expr = expr->IgnoreParenImpCasts(); | 
 |     switch (expr->getStmtClass()) { | 
 |       case Stmt::ArraySubscriptExprClass: { | 
 |         const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); | 
 |         CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, | 
 |                          AllowOnePastEnd > 0); | 
 |         expr = ASE->getBase(); | 
 |         break; | 
 |       } | 
 |       case Stmt::MemberExprClass: { | 
 |         expr = cast<MemberExpr>(expr)->getBase(); | 
 |         break; | 
 |       } | 
 |       case Stmt::ArraySectionExprClass: { | 
 |         const ArraySectionExpr *ASE = cast<ArraySectionExpr>(expr); | 
 |         // FIXME: We should probably be checking all of the elements to the | 
 |         // 'length' here as well. | 
 |         if (ASE->getLowerBound()) | 
 |           CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), | 
 |                            /*ASE=*/nullptr, AllowOnePastEnd > 0); | 
 |         return; | 
 |       } | 
 |       case Stmt::UnaryOperatorClass: { | 
 |         // Only unwrap the * and & unary operators | 
 |         const UnaryOperator *UO = cast<UnaryOperator>(expr); | 
 |         expr = UO->getSubExpr(); | 
 |         switch (UO->getOpcode()) { | 
 |           case UO_AddrOf: | 
 |             AllowOnePastEnd++; | 
 |             break; | 
 |           case UO_Deref: | 
 |             AllowOnePastEnd--; | 
 |             break; | 
 |           default: | 
 |             return; | 
 |         } | 
 |         break; | 
 |       } | 
 |       case Stmt::ConditionalOperatorClass: { | 
 |         const ConditionalOperator *cond = cast<ConditionalOperator>(expr); | 
 |         if (const Expr *lhs = cond->getLHS()) | 
 |           CheckArrayAccess(lhs); | 
 |         if (const Expr *rhs = cond->getRHS()) | 
 |           CheckArrayAccess(rhs); | 
 |         return; | 
 |       } | 
 |       case Stmt::CXXOperatorCallExprClass: { | 
 |         const auto *OCE = cast<CXXOperatorCallExpr>(expr); | 
 |         for (const auto *Arg : OCE->arguments()) | 
 |           CheckArrayAccess(Arg); | 
 |         return; | 
 |       } | 
 |       default: | 
 |         return; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc, | 
 |                                      Expr *RHS, bool isProperty) { | 
 |   // Check if RHS is an Objective-C object literal, which also can get | 
 |   // immediately zapped in a weak reference.  Note that we explicitly | 
 |   // allow ObjCStringLiterals, since those are designed to never really die. | 
 |   RHS = RHS->IgnoreParenImpCasts(); | 
 |  | 
 |   // This enum needs to match with the 'select' in | 
 |   // warn_objc_arc_literal_assign (off-by-1). | 
 |   SemaObjC::ObjCLiteralKind Kind = S.ObjC().CheckLiteralKind(RHS); | 
 |   if (Kind == SemaObjC::LK_String || Kind == SemaObjC::LK_None) | 
 |     return false; | 
 |  | 
 |   S.Diag(Loc, diag::warn_arc_literal_assign) | 
 |     << (unsigned) Kind | 
 |     << (isProperty ? 0 : 1) | 
 |     << RHS->getSourceRange(); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc, | 
 |                                     Qualifiers::ObjCLifetime LT, | 
 |                                     Expr *RHS, bool isProperty) { | 
 |   // Strip off any implicit cast added to get to the one ARC-specific. | 
 |   while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { | 
 |     if (cast->getCastKind() == CK_ARCConsumeObject) { | 
 |       S.Diag(Loc, diag::warn_arc_retained_assign) | 
 |         << (LT == Qualifiers::OCL_ExplicitNone) | 
 |         << (isProperty ? 0 : 1) | 
 |         << RHS->getSourceRange(); | 
 |       return true; | 
 |     } | 
 |     RHS = cast->getSubExpr(); | 
 |   } | 
 |  | 
 |   if (LT == Qualifiers::OCL_Weak && | 
 |       checkUnsafeAssignLiteral(S, Loc, RHS, isProperty)) | 
 |     return true; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::checkUnsafeAssigns(SourceLocation Loc, | 
 |                               QualType LHS, Expr *RHS) { | 
 |   Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); | 
 |  | 
 |   if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone) | 
 |     return false; | 
 |  | 
 |   if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false)) | 
 |     return true; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | void Sema::checkUnsafeExprAssigns(SourceLocation Loc, | 
 |                               Expr *LHS, Expr *RHS) { | 
 |   QualType LHSType; | 
 |   // PropertyRef on LHS type need be directly obtained from | 
 |   // its declaration as it has a PseudoType. | 
 |   ObjCPropertyRefExpr *PRE | 
 |     = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens()); | 
 |   if (PRE && !PRE->isImplicitProperty()) { | 
 |     const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); | 
 |     if (PD) | 
 |       LHSType = PD->getType(); | 
 |   } | 
 |  | 
 |   if (LHSType.isNull()) | 
 |     LHSType = LHS->getType(); | 
 |  | 
 |   Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); | 
 |  | 
 |   if (LT == Qualifiers::OCL_Weak) { | 
 |     if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) | 
 |       getCurFunction()->markSafeWeakUse(LHS); | 
 |   } | 
 |  | 
 |   if (checkUnsafeAssigns(Loc, LHSType, RHS)) | 
 |     return; | 
 |  | 
 |   // FIXME. Check for other life times. | 
 |   if (LT != Qualifiers::OCL_None) | 
 |     return; | 
 |  | 
 |   if (PRE) { | 
 |     if (PRE->isImplicitProperty()) | 
 |       return; | 
 |     const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); | 
 |     if (!PD) | 
 |       return; | 
 |  | 
 |     unsigned Attributes = PD->getPropertyAttributes(); | 
 |     if (Attributes & ObjCPropertyAttribute::kind_assign) { | 
 |       // when 'assign' attribute was not explicitly specified | 
 |       // by user, ignore it and rely on property type itself | 
 |       // for lifetime info. | 
 |       unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten(); | 
 |       if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) && | 
 |           LHSType->isObjCRetainableType()) | 
 |         return; | 
 |  | 
 |       while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { | 
 |         if (cast->getCastKind() == CK_ARCConsumeObject) { | 
 |           Diag(Loc, diag::warn_arc_retained_property_assign) | 
 |           << RHS->getSourceRange(); | 
 |           return; | 
 |         } | 
 |         RHS = cast->getSubExpr(); | 
 |       } | 
 |     } else if (Attributes & ObjCPropertyAttribute::kind_weak) { | 
 |       if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true)) | 
 |         return; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | //===--- CHECK: Empty statement body (-Wempty-body) ---------------------===// | 
 |  | 
 | static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, | 
 |                                         SourceLocation StmtLoc, | 
 |                                         const NullStmt *Body) { | 
 |   // Do not warn if the body is a macro that expands to nothing, e.g: | 
 |   // | 
 |   // #define CALL(x) | 
 |   // if (condition) | 
 |   //   CALL(0); | 
 |   if (Body->hasLeadingEmptyMacro()) | 
 |     return false; | 
 |  | 
 |   // Get line numbers of statement and body. | 
 |   bool StmtLineInvalid; | 
 |   unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc, | 
 |                                                       &StmtLineInvalid); | 
 |   if (StmtLineInvalid) | 
 |     return false; | 
 |  | 
 |   bool BodyLineInvalid; | 
 |   unsigned BodyLine = SourceMgr.getSpellingLineNumber(Body->getSemiLoc(), | 
 |                                                       &BodyLineInvalid); | 
 |   if (BodyLineInvalid) | 
 |     return false; | 
 |  | 
 |   // Warn if null statement and body are on the same line. | 
 |   if (StmtLine != BodyLine) | 
 |     return false; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, | 
 |                                  const Stmt *Body, | 
 |                                  unsigned DiagID) { | 
 |   // Since this is a syntactic check, don't emit diagnostic for template | 
 |   // instantiations, this just adds noise. | 
 |   if (CurrentInstantiationScope) | 
 |     return; | 
 |  | 
 |   // The body should be a null statement. | 
 |   const NullStmt *NBody = dyn_cast<NullStmt>(Body); | 
 |   if (!NBody) | 
 |     return; | 
 |  | 
 |   // Do the usual checks. | 
 |   if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody)) | 
 |     return; | 
 |  | 
 |   Diag(NBody->getSemiLoc(), DiagID); | 
 |   Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line); | 
 | } | 
 |  | 
 | void Sema::DiagnoseEmptyLoopBody(const Stmt *S, | 
 |                                  const Stmt *PossibleBody) { | 
 |   assert(!CurrentInstantiationScope); // Ensured by caller | 
 |  | 
 |   SourceLocation StmtLoc; | 
 |   const Stmt *Body; | 
 |   unsigned DiagID; | 
 |   if (const ForStmt *FS = dyn_cast<ForStmt>(S)) { | 
 |     StmtLoc = FS->getRParenLoc(); | 
 |     Body = FS->getBody(); | 
 |     DiagID = diag::warn_empty_for_body; | 
 |   } else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) { | 
 |     StmtLoc = WS->getRParenLoc(); | 
 |     Body = WS->getBody(); | 
 |     DiagID = diag::warn_empty_while_body; | 
 |   } else | 
 |     return; // Neither `for' nor `while'. | 
 |  | 
 |   // The body should be a null statement. | 
 |   const NullStmt *NBody = dyn_cast<NullStmt>(Body); | 
 |   if (!NBody) | 
 |     return; | 
 |  | 
 |   // Skip expensive checks if diagnostic is disabled. | 
 |   if (Diags.isIgnored(DiagID, NBody->getSemiLoc())) | 
 |     return; | 
 |  | 
 |   // Do the usual checks. | 
 |   if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody)) | 
 |     return; | 
 |  | 
 |   // `for(...);' and `while(...);' are popular idioms, so in order to keep | 
 |   // noise level low, emit diagnostics only if for/while is followed by a | 
 |   // CompoundStmt, e.g.: | 
 |   //    for (int i = 0; i < n; i++); | 
 |   //    { | 
 |   //      a(i); | 
 |   //    } | 
 |   // or if for/while is followed by a statement with more indentation | 
 |   // than for/while itself: | 
 |   //    for (int i = 0; i < n; i++); | 
 |   //      a(i); | 
 |   bool ProbableTypo = isa<CompoundStmt>(PossibleBody); | 
 |   if (!ProbableTypo) { | 
 |     bool BodyColInvalid; | 
 |     unsigned BodyCol = SourceMgr.getPresumedColumnNumber( | 
 |         PossibleBody->getBeginLoc(), &BodyColInvalid); | 
 |     if (BodyColInvalid) | 
 |       return; | 
 |  | 
 |     bool StmtColInvalid; | 
 |     unsigned StmtCol = | 
 |         SourceMgr.getPresumedColumnNumber(S->getBeginLoc(), &StmtColInvalid); | 
 |     if (StmtColInvalid) | 
 |       return; | 
 |  | 
 |     if (BodyCol > StmtCol) | 
 |       ProbableTypo = true; | 
 |   } | 
 |  | 
 |   if (ProbableTypo) { | 
 |     Diag(NBody->getSemiLoc(), DiagID); | 
 |     Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line); | 
 |   } | 
 | } | 
 |  | 
 | //===--- CHECK: Warn on self move with std::move. -------------------------===// | 
 |  | 
 | void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, | 
 |                              SourceLocation OpLoc) { | 
 |   if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc)) | 
 |     return; | 
 |  | 
 |   if (inTemplateInstantiation()) | 
 |     return; | 
 |  | 
 |   // Strip parens and casts away. | 
 |   LHSExpr = LHSExpr->IgnoreParenImpCasts(); | 
 |   RHSExpr = RHSExpr->IgnoreParenImpCasts(); | 
 |  | 
 |   // Check for a call to std::move or for a static_cast<T&&>(..) to an xvalue | 
 |   // which we can treat as an inlined std::move | 
 |   if (const auto *CE = dyn_cast<CallExpr>(RHSExpr); | 
 |       CE && CE->getNumArgs() == 1 && CE->isCallToStdMove()) | 
 |     RHSExpr = CE->getArg(0); | 
 |   else if (const auto *CXXSCE = dyn_cast<CXXStaticCastExpr>(RHSExpr); | 
 |            CXXSCE && CXXSCE->isXValue()) | 
 |     RHSExpr = CXXSCE->getSubExpr(); | 
 |   else | 
 |     return; | 
 |  | 
 |   const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); | 
 |   const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); | 
 |  | 
 |   // Two DeclRefExpr's, check that the decls are the same. | 
 |   if (LHSDeclRef && RHSDeclRef) { | 
 |     if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) | 
 |       return; | 
 |     if (LHSDeclRef->getDecl()->getCanonicalDecl() != | 
 |         RHSDeclRef->getDecl()->getCanonicalDecl()) | 
 |       return; | 
 |  | 
 |     auto D = Diag(OpLoc, diag::warn_self_move) | 
 |              << LHSExpr->getType() << LHSExpr->getSourceRange() | 
 |              << RHSExpr->getSourceRange(); | 
 |     if (const FieldDecl *F = | 
 |             getSelfAssignmentClassMemberCandidate(RHSDeclRef->getDecl())) | 
 |       D << 1 << F | 
 |         << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->"); | 
 |     else | 
 |       D << 0; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Member variables require a different approach to check for self moves. | 
 |   // MemberExpr's are the same if every nested MemberExpr refers to the same | 
 |   // Decl and that the base Expr's are DeclRefExpr's with the same Decl or | 
 |   // the base Expr's are CXXThisExpr's. | 
 |   const Expr *LHSBase = LHSExpr; | 
 |   const Expr *RHSBase = RHSExpr; | 
 |   const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr); | 
 |   const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr); | 
 |   if (!LHSME || !RHSME) | 
 |     return; | 
 |  | 
 |   while (LHSME && RHSME) { | 
 |     if (LHSME->getMemberDecl()->getCanonicalDecl() != | 
 |         RHSME->getMemberDecl()->getCanonicalDecl()) | 
 |       return; | 
 |  | 
 |     LHSBase = LHSME->getBase(); | 
 |     RHSBase = RHSME->getBase(); | 
 |     LHSME = dyn_cast<MemberExpr>(LHSBase); | 
 |     RHSME = dyn_cast<MemberExpr>(RHSBase); | 
 |   } | 
 |  | 
 |   LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase); | 
 |   RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase); | 
 |   if (LHSDeclRef && RHSDeclRef) { | 
 |     if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) | 
 |       return; | 
 |     if (LHSDeclRef->getDecl()->getCanonicalDecl() != | 
 |         RHSDeclRef->getDecl()->getCanonicalDecl()) | 
 |       return; | 
 |  | 
 |     Diag(OpLoc, diag::warn_self_move) | 
 |         << LHSExpr->getType() << 0 << LHSExpr->getSourceRange() | 
 |         << RHSExpr->getSourceRange(); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase)) | 
 |     Diag(OpLoc, diag::warn_self_move) | 
 |         << LHSExpr->getType() << 0 << LHSExpr->getSourceRange() | 
 |         << RHSExpr->getSourceRange(); | 
 | } | 
 |  | 
 | //===--- Layout compatibility ----------------------------------------------// | 
 |  | 
 | static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2); | 
 |  | 
 | /// Check if two enumeration types are layout-compatible. | 
 | static bool isLayoutCompatible(const ASTContext &C, const EnumDecl *ED1, | 
 |                                const EnumDecl *ED2) { | 
 |   // C++11 [dcl.enum] p8: | 
 |   // Two enumeration types are layout-compatible if they have the same | 
 |   // underlying type. | 
 |   return ED1->isComplete() && ED2->isComplete() && | 
 |          C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType()); | 
 | } | 
 |  | 
 | /// Check if two fields are layout-compatible. | 
 | /// Can be used on union members, which are exempt from alignment requirement | 
 | /// of common initial sequence. | 
 | static bool isLayoutCompatible(const ASTContext &C, const FieldDecl *Field1, | 
 |                                const FieldDecl *Field2, | 
 |                                bool AreUnionMembers = false) { | 
 | #ifndef NDEBUG | 
 |   CanQualType Field1Parent = C.getCanonicalTagType(Field1->getParent()); | 
 |   CanQualType Field2Parent = C.getCanonicalTagType(Field2->getParent()); | 
 |   assert(((Field1Parent->isStructureOrClassType() && | 
 |            Field2Parent->isStructureOrClassType()) || | 
 |           (Field1Parent->isUnionType() && Field2Parent->isUnionType())) && | 
 |          "Can't evaluate layout compatibility between a struct field and a " | 
 |          "union field."); | 
 |   assert(((!AreUnionMembers && Field1Parent->isStructureOrClassType()) || | 
 |           (AreUnionMembers && Field1Parent->isUnionType())) && | 
 |          "AreUnionMembers should be 'true' for union fields (only)."); | 
 | #endif | 
 |  | 
 |   if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) | 
 |     return false; | 
 |  | 
 |   if (Field1->isBitField() != Field2->isBitField()) | 
 |     return false; | 
 |  | 
 |   if (Field1->isBitField()) { | 
 |     // Make sure that the bit-fields are the same length. | 
 |     unsigned Bits1 = Field1->getBitWidthValue(); | 
 |     unsigned Bits2 = Field2->getBitWidthValue(); | 
 |  | 
 |     if (Bits1 != Bits2) | 
 |       return false; | 
 |   } | 
 |  | 
 |   if (Field1->hasAttr<clang::NoUniqueAddressAttr>() || | 
 |       Field2->hasAttr<clang::NoUniqueAddressAttr>()) | 
 |     return false; | 
 |  | 
 |   if (!AreUnionMembers && | 
 |       Field1->getMaxAlignment() != Field2->getMaxAlignment()) | 
 |     return false; | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /// Check if two standard-layout structs are layout-compatible. | 
 | /// (C++11 [class.mem] p17) | 
 | static bool isLayoutCompatibleStruct(const ASTContext &C, const RecordDecl *RD1, | 
 |                                      const RecordDecl *RD2) { | 
 |   // Get to the class where the fields are declared | 
 |   if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) | 
 |     RD1 = D1CXX->getStandardLayoutBaseWithFields(); | 
 |  | 
 |   if (const CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(RD2)) | 
 |     RD2 = D2CXX->getStandardLayoutBaseWithFields(); | 
 |  | 
 |   // Check the fields. | 
 |   return llvm::equal(RD1->fields(), RD2->fields(), | 
 |                      [&C](const FieldDecl *F1, const FieldDecl *F2) -> bool { | 
 |                        return isLayoutCompatible(C, F1, F2); | 
 |                      }); | 
 | } | 
 |  | 
 | /// Check if two standard-layout unions are layout-compatible. | 
 | /// (C++11 [class.mem] p18) | 
 | static bool isLayoutCompatibleUnion(const ASTContext &C, const RecordDecl *RD1, | 
 |                                     const RecordDecl *RD2) { | 
 |   llvm::SmallPtrSet<const FieldDecl *, 8> UnmatchedFields(llvm::from_range, | 
 |                                                           RD2->fields()); | 
 |  | 
 |   for (auto *Field1 : RD1->fields()) { | 
 |     auto I = UnmatchedFields.begin(); | 
 |     auto E = UnmatchedFields.end(); | 
 |  | 
 |     for ( ; I != E; ++I) { | 
 |       if (isLayoutCompatible(C, Field1, *I, /*IsUnionMember=*/true)) { | 
 |         bool Result = UnmatchedFields.erase(*I); | 
 |         (void) Result; | 
 |         assert(Result); | 
 |         break; | 
 |       } | 
 |     } | 
 |     if (I == E) | 
 |       return false; | 
 |   } | 
 |  | 
 |   return UnmatchedFields.empty(); | 
 | } | 
 |  | 
 | static bool isLayoutCompatible(const ASTContext &C, const RecordDecl *RD1, | 
 |                                const RecordDecl *RD2) { | 
 |   if (RD1->isUnion() != RD2->isUnion()) | 
 |     return false; | 
 |  | 
 |   if (RD1->isUnion()) | 
 |     return isLayoutCompatibleUnion(C, RD1, RD2); | 
 |   else | 
 |     return isLayoutCompatibleStruct(C, RD1, RD2); | 
 | } | 
 |  | 
 | /// Check if two types are layout-compatible in C++11 sense. | 
 | static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) { | 
 |   if (T1.isNull() || T2.isNull()) | 
 |     return false; | 
 |  | 
 |   // C++20 [basic.types] p11: | 
 |   // Two types cv1 T1 and cv2 T2 are layout-compatible types | 
 |   // if T1 and T2 are the same type, layout-compatible enumerations (9.7.1), | 
 |   // or layout-compatible standard-layout class types (11.4). | 
 |   T1 = T1.getCanonicalType().getUnqualifiedType(); | 
 |   T2 = T2.getCanonicalType().getUnqualifiedType(); | 
 |  | 
 |   if (C.hasSameType(T1, T2)) | 
 |     return true; | 
 |  | 
 |   const Type::TypeClass TC1 = T1->getTypeClass(); | 
 |   const Type::TypeClass TC2 = T2->getTypeClass(); | 
 |  | 
 |   if (TC1 != TC2) | 
 |     return false; | 
 |  | 
 |   if (TC1 == Type::Enum) | 
 |     return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl()); | 
 |   if (TC1 == Type::Record) { | 
 |     if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType()) | 
 |       return false; | 
 |  | 
 |     return isLayoutCompatible(C, T1->castAsRecordDecl(), | 
 |                               T2->castAsRecordDecl()); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const { | 
 |   return isLayoutCompatible(getASTContext(), T1, T2); | 
 | } | 
 |  | 
 | //===-------------- Pointer interconvertibility ----------------------------// | 
 |  | 
 | bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, | 
 |                                            const TypeSourceInfo *Derived) { | 
 |   QualType BaseT = Base->getType()->getCanonicalTypeUnqualified(); | 
 |   QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified(); | 
 |  | 
 |   if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() && | 
 |       getASTContext().hasSameType(BaseT, DerivedT)) | 
 |     return true; | 
 |  | 
 |   if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT)) | 
 |     return false; | 
 |  | 
 |   // Per [basic.compound]/4.3, containing object has to be standard-layout. | 
 |   if (DerivedT->getAsCXXRecordDecl()->isStandardLayout()) | 
 |     return true; | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// | 
 |  | 
 | /// Given a type tag expression find the type tag itself. | 
 | /// | 
 | /// \param TypeExpr Type tag expression, as it appears in user's code. | 
 | /// | 
 | /// \param VD Declaration of an identifier that appears in a type tag. | 
 | /// | 
 | /// \param MagicValue Type tag magic value. | 
 | /// | 
 | /// \param isConstantEvaluated whether the evalaution should be performed in | 
 |  | 
 | /// constant context. | 
 | static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, | 
 |                             const ValueDecl **VD, uint64_t *MagicValue, | 
 |                             bool isConstantEvaluated) { | 
 |   while(true) { | 
 |     if (!TypeExpr) | 
 |       return false; | 
 |  | 
 |     TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts(); | 
 |  | 
 |     switch (TypeExpr->getStmtClass()) { | 
 |     case Stmt::UnaryOperatorClass: { | 
 |       const UnaryOperator *UO = cast<UnaryOperator>(TypeExpr); | 
 |       if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) { | 
 |         TypeExpr = UO->getSubExpr(); | 
 |         continue; | 
 |       } | 
 |       return false; | 
 |     } | 
 |  | 
 |     case Stmt::DeclRefExprClass: { | 
 |       const DeclRefExpr *DRE = cast<DeclRefExpr>(TypeExpr); | 
 |       *VD = DRE->getDecl(); | 
 |       return true; | 
 |     } | 
 |  | 
 |     case Stmt::IntegerLiteralClass: { | 
 |       const IntegerLiteral *IL = cast<IntegerLiteral>(TypeExpr); | 
 |       llvm::APInt MagicValueAPInt = IL->getValue(); | 
 |       if (MagicValueAPInt.getActiveBits() <= 64) { | 
 |         *MagicValue = MagicValueAPInt.getZExtValue(); | 
 |         return true; | 
 |       } else | 
 |         return false; | 
 |     } | 
 |  | 
 |     case Stmt::BinaryConditionalOperatorClass: | 
 |     case Stmt::ConditionalOperatorClass: { | 
 |       const AbstractConditionalOperator *ACO = | 
 |           cast<AbstractConditionalOperator>(TypeExpr); | 
 |       bool Result; | 
 |       if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx, | 
 |                                                      isConstantEvaluated)) { | 
 |         if (Result) | 
 |           TypeExpr = ACO->getTrueExpr(); | 
 |         else | 
 |           TypeExpr = ACO->getFalseExpr(); | 
 |         continue; | 
 |       } | 
 |       return false; | 
 |     } | 
 |  | 
 |     case Stmt::BinaryOperatorClass: { | 
 |       const BinaryOperator *BO = cast<BinaryOperator>(TypeExpr); | 
 |       if (BO->getOpcode() == BO_Comma) { | 
 |         TypeExpr = BO->getRHS(); | 
 |         continue; | 
 |       } | 
 |       return false; | 
 |     } | 
 |  | 
 |     default: | 
 |       return false; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// Retrieve the C type corresponding to type tag TypeExpr. | 
 | /// | 
 | /// \param TypeExpr Expression that specifies a type tag. | 
 | /// | 
 | /// \param MagicValues Registered magic values. | 
 | /// | 
 | /// \param FoundWrongKind Set to true if a type tag was found, but of a wrong | 
 | ///        kind. | 
 | /// | 
 | /// \param TypeInfo Information about the corresponding C type. | 
 | /// | 
 | /// \param isConstantEvaluated whether the evalaution should be performed in | 
 | /// constant context. | 
 | /// | 
 | /// \returns true if the corresponding C type was found. | 
 | static bool GetMatchingCType( | 
 |     const IdentifierInfo *ArgumentKind, const Expr *TypeExpr, | 
 |     const ASTContext &Ctx, | 
 |     const llvm::DenseMap<Sema::TypeTagMagicValue, Sema::TypeTagData> | 
 |         *MagicValues, | 
 |     bool &FoundWrongKind, Sema::TypeTagData &TypeInfo, | 
 |     bool isConstantEvaluated) { | 
 |   FoundWrongKind = false; | 
 |  | 
 |   // Variable declaration that has type_tag_for_datatype attribute. | 
 |   const ValueDecl *VD = nullptr; | 
 |  | 
 |   uint64_t MagicValue; | 
 |  | 
 |   if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue, isConstantEvaluated)) | 
 |     return false; | 
 |  | 
 |   if (VD) { | 
 |     if (TypeTagForDatatypeAttr *I = VD->getAttr<TypeTagForDatatypeAttr>()) { | 
 |       if (I->getArgumentKind() != ArgumentKind) { | 
 |         FoundWrongKind = true; | 
 |         return false; | 
 |       } | 
 |       TypeInfo.Type = I->getMatchingCType(); | 
 |       TypeInfo.LayoutCompatible = I->getLayoutCompatible(); | 
 |       TypeInfo.MustBeNull = I->getMustBeNull(); | 
 |       return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (!MagicValues) | 
 |     return false; | 
 |  | 
 |   llvm::DenseMap<Sema::TypeTagMagicValue, | 
 |                  Sema::TypeTagData>::const_iterator I = | 
 |       MagicValues->find(std::make_pair(ArgumentKind, MagicValue)); | 
 |   if (I == MagicValues->end()) | 
 |     return false; | 
 |  | 
 |   TypeInfo = I->second; | 
 |   return true; | 
 | } | 
 |  | 
 | void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, | 
 |                                       uint64_t MagicValue, QualType Type, | 
 |                                       bool LayoutCompatible, | 
 |                                       bool MustBeNull) { | 
 |   if (!TypeTagForDatatypeMagicValues) | 
 |     TypeTagForDatatypeMagicValues.reset( | 
 |         new llvm::DenseMap<TypeTagMagicValue, TypeTagData>); | 
 |  | 
 |   TypeTagMagicValue Magic(ArgumentKind, MagicValue); | 
 |   (*TypeTagForDatatypeMagicValues)[Magic] = | 
 |       TypeTagData(Type, LayoutCompatible, MustBeNull); | 
 | } | 
 |  | 
 | static bool IsSameCharType(QualType T1, QualType T2) { | 
 |   const BuiltinType *BT1 = T1->getAs<BuiltinType>(); | 
 |   if (!BT1) | 
 |     return false; | 
 |  | 
 |   const BuiltinType *BT2 = T2->getAs<BuiltinType>(); | 
 |   if (!BT2) | 
 |     return false; | 
 |  | 
 |   BuiltinType::Kind T1Kind = BT1->getKind(); | 
 |   BuiltinType::Kind T2Kind = BT2->getKind(); | 
 |  | 
 |   return (T1Kind == BuiltinType::SChar  && T2Kind == BuiltinType::Char_S) || | 
 |          (T1Kind == BuiltinType::UChar  && T2Kind == BuiltinType::Char_U) || | 
 |          (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || | 
 |          (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); | 
 | } | 
 |  | 
 | void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, | 
 |                                     const ArrayRef<const Expr *> ExprArgs, | 
 |                                     SourceLocation CallSiteLoc) { | 
 |   const IdentifierInfo *ArgumentKind = Attr->getArgumentKind(); | 
 |   bool IsPointerAttr = Attr->getIsPointer(); | 
 |  | 
 |   // Retrieve the argument representing the 'type_tag'. | 
 |   unsigned TypeTagIdxAST = Attr->getTypeTagIdx().getASTIndex(); | 
 |   if (TypeTagIdxAST >= ExprArgs.size()) { | 
 |     Diag(CallSiteLoc, diag::err_tag_index_out_of_range) | 
 |         << 0 << Attr->getTypeTagIdx().getSourceIndex(); | 
 |     return; | 
 |   } | 
 |   const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST]; | 
 |   bool FoundWrongKind; | 
 |   TypeTagData TypeInfo; | 
 |   if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, | 
 |                         TypeTagForDatatypeMagicValues.get(), FoundWrongKind, | 
 |                         TypeInfo, isConstantEvaluatedContext())) { | 
 |     if (FoundWrongKind) | 
 |       Diag(TypeTagExpr->getExprLoc(), | 
 |            diag::warn_type_tag_for_datatype_wrong_kind) | 
 |         << TypeTagExpr->getSourceRange(); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Retrieve the argument representing the 'arg_idx'. | 
 |   unsigned ArgumentIdxAST = Attr->getArgumentIdx().getASTIndex(); | 
 |   if (ArgumentIdxAST >= ExprArgs.size()) { | 
 |     Diag(CallSiteLoc, diag::err_tag_index_out_of_range) | 
 |         << 1 << Attr->getArgumentIdx().getSourceIndex(); | 
 |     return; | 
 |   } | 
 |   const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST]; | 
 |   if (IsPointerAttr) { | 
 |     // Skip implicit cast of pointer to `void *' (as a function argument). | 
 |     if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr)) | 
 |       if (ICE->getType()->isVoidPointerType() && | 
 |           ICE->getCastKind() == CK_BitCast) | 
 |         ArgumentExpr = ICE->getSubExpr(); | 
 |   } | 
 |   QualType ArgumentType = ArgumentExpr->getType(); | 
 |  | 
 |   // Passing a `void*' pointer shouldn't trigger a warning. | 
 |   if (IsPointerAttr && ArgumentType->isVoidPointerType()) | 
 |     return; | 
 |  | 
 |   if (TypeInfo.MustBeNull) { | 
 |     // Type tag with matching void type requires a null pointer. | 
 |     if (!ArgumentExpr->isNullPointerConstant(Context, | 
 |                                              Expr::NPC_ValueDependentIsNotNull)) { | 
 |       Diag(ArgumentExpr->getExprLoc(), | 
 |            diag::warn_type_safety_null_pointer_required) | 
 |           << ArgumentKind->getName() | 
 |           << ArgumentExpr->getSourceRange() | 
 |           << TypeTagExpr->getSourceRange(); | 
 |     } | 
 |     return; | 
 |   } | 
 |  | 
 |   QualType RequiredType = TypeInfo.Type; | 
 |   if (IsPointerAttr) | 
 |     RequiredType = Context.getPointerType(RequiredType); | 
 |  | 
 |   bool mismatch = false; | 
 |   if (!TypeInfo.LayoutCompatible) { | 
 |     mismatch = !Context.hasSameType(ArgumentType, RequiredType); | 
 |  | 
 |     // C++11 [basic.fundamental] p1: | 
 |     // Plain char, signed char, and unsigned char are three distinct types. | 
 |     // | 
 |     // But we treat plain `char' as equivalent to `signed char' or `unsigned | 
 |     // char' depending on the current char signedness mode. | 
 |     if (mismatch) | 
 |       if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(), | 
 |                                            RequiredType->getPointeeType())) || | 
 |           (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType))) | 
 |         mismatch = false; | 
 |   } else | 
 |     if (IsPointerAttr) | 
 |       mismatch = !isLayoutCompatible(Context, | 
 |                                      ArgumentType->getPointeeType(), | 
 |                                      RequiredType->getPointeeType()); | 
 |     else | 
 |       mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType); | 
 |  | 
 |   if (mismatch) | 
 |     Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch) | 
 |         << ArgumentType << ArgumentKind | 
 |         << TypeInfo.LayoutCompatible << RequiredType | 
 |         << ArgumentExpr->getSourceRange() | 
 |         << TypeTagExpr->getSourceRange(); | 
 | } | 
 |  | 
 | void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, | 
 |                                          CharUnits Alignment) { | 
 |   currentEvaluationContext().MisalignedMembers.emplace_back(E, RD, MD, | 
 |                                                             Alignment); | 
 | } | 
 |  | 
 | void Sema::DiagnoseMisalignedMembers() { | 
 |   for (MisalignedMember &m : currentEvaluationContext().MisalignedMembers) { | 
 |     const NamedDecl *ND = m.RD; | 
 |     if (ND->getName().empty()) { | 
 |       if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl()) | 
 |         ND = TD; | 
 |     } | 
 |     Diag(m.E->getBeginLoc(), diag::warn_taking_address_of_packed_member) | 
 |         << m.MD << ND << m.E->getSourceRange(); | 
 |   } | 
 |   currentEvaluationContext().MisalignedMembers.clear(); | 
 | } | 
 |  | 
 | void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { | 
 |   E = E->IgnoreParens(); | 
 |   if (!T->isPointerType() && !T->isIntegerType() && !T->isDependentType()) | 
 |     return; | 
 |   if (isa<UnaryOperator>(E) && | 
 |       cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { | 
 |     auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); | 
 |     if (isa<MemberExpr>(Op)) { | 
 |       auto &MisalignedMembersForExpr = | 
 |           currentEvaluationContext().MisalignedMembers; | 
 |       auto *MA = llvm::find(MisalignedMembersForExpr, MisalignedMember(Op)); | 
 |       if (MA != MisalignedMembersForExpr.end() && | 
 |           (T->isDependentType() || T->isIntegerType() || | 
 |            (T->isPointerType() && (T->getPointeeType()->isIncompleteType() || | 
 |                                    Context.getTypeAlignInChars( | 
 |                                        T->getPointeeType()) <= MA->Alignment)))) | 
 |         MisalignedMembersForExpr.erase(MA); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void Sema::RefersToMemberWithReducedAlignment( | 
 |     Expr *E, | 
 |     llvm::function_ref<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)> | 
 |         Action) { | 
 |   const auto *ME = dyn_cast<MemberExpr>(E); | 
 |   if (!ME) | 
 |     return; | 
 |  | 
 |   // No need to check expressions with an __unaligned-qualified type. | 
 |   if (E->getType().getQualifiers().hasUnaligned()) | 
 |     return; | 
 |  | 
 |   // For a chain of MemberExpr like "a.b.c.d" this list | 
 |   // will keep FieldDecl's like [d, c, b]. | 
 |   SmallVector<FieldDecl *, 4> ReverseMemberChain; | 
 |   const MemberExpr *TopME = nullptr; | 
 |   bool AnyIsPacked = false; | 
 |   do { | 
 |     QualType BaseType = ME->getBase()->getType(); | 
 |     if (BaseType->isDependentType()) | 
 |       return; | 
 |     if (ME->isArrow()) | 
 |       BaseType = BaseType->getPointeeType(); | 
 |     auto *RD = BaseType->castAsRecordDecl(); | 
 |     if (RD->isInvalidDecl()) | 
 |       return; | 
 |  | 
 |     ValueDecl *MD = ME->getMemberDecl(); | 
 |     auto *FD = dyn_cast<FieldDecl>(MD); | 
 |     // We do not care about non-data members. | 
 |     if (!FD || FD->isInvalidDecl()) | 
 |       return; | 
 |  | 
 |     AnyIsPacked = | 
 |         AnyIsPacked || (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>()); | 
 |     ReverseMemberChain.push_back(FD); | 
 |  | 
 |     TopME = ME; | 
 |     ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParens()); | 
 |   } while (ME); | 
 |   assert(TopME && "We did not compute a topmost MemberExpr!"); | 
 |  | 
 |   // Not the scope of this diagnostic. | 
 |   if (!AnyIsPacked) | 
 |     return; | 
 |  | 
 |   const Expr *TopBase = TopME->getBase()->IgnoreParenImpCasts(); | 
 |   const auto *DRE = dyn_cast<DeclRefExpr>(TopBase); | 
 |   // TODO: The innermost base of the member expression may be too complicated. | 
 |   // For now, just disregard these cases. This is left for future | 
 |   // improvement. | 
 |   if (!DRE && !isa<CXXThisExpr>(TopBase)) | 
 |       return; | 
 |  | 
 |   // Alignment expected by the whole expression. | 
 |   CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType()); | 
 |  | 
 |   // No need to do anything else with this case. | 
 |   if (ExpectedAlignment.isOne()) | 
 |     return; | 
 |  | 
 |   // Synthesize offset of the whole access. | 
 |   CharUnits Offset; | 
 |   for (const FieldDecl *FD : llvm::reverse(ReverseMemberChain)) | 
 |     Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(FD)); | 
 |  | 
 |   // Compute the CompleteObjectAlignment as the alignment of the whole chain. | 
 |   CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars( | 
 |       Context.getCanonicalTagType(ReverseMemberChain.back()->getParent())); | 
 |  | 
 |   // The base expression of the innermost MemberExpr may give | 
 |   // stronger guarantees than the class containing the member. | 
 |   if (DRE && !TopME->isArrow()) { | 
 |     const ValueDecl *VD = DRE->getDecl(); | 
 |     if (!VD->getType()->isReferenceType()) | 
 |       CompleteObjectAlignment = | 
 |           std::max(CompleteObjectAlignment, Context.getDeclAlign(VD)); | 
 |   } | 
 |  | 
 |   // Check if the synthesized offset fulfills the alignment. | 
 |   if (!Offset.isMultipleOf(ExpectedAlignment) || | 
 |       // It may fulfill the offset it but the effective alignment may still be | 
 |       // lower than the expected expression alignment. | 
 |       CompleteObjectAlignment < ExpectedAlignment) { | 
 |     // If this happens, we want to determine a sensible culprit of this. | 
 |     // Intuitively, watching the chain of member expressions from right to | 
 |     // left, we start with the required alignment (as required by the field | 
 |     // type) but some packed attribute in that chain has reduced the alignment. | 
 |     // It may happen that another packed structure increases it again. But if | 
 |     // we are here such increase has not been enough. So pointing the first | 
 |     // FieldDecl that either is packed or else its RecordDecl is, | 
 |     // seems reasonable. | 
 |     FieldDecl *FD = nullptr; | 
 |     CharUnits Alignment; | 
 |     for (FieldDecl *FDI : ReverseMemberChain) { | 
 |       if (FDI->hasAttr<PackedAttr>() || | 
 |           FDI->getParent()->hasAttr<PackedAttr>()) { | 
 |         FD = FDI; | 
 |         Alignment = std::min(Context.getTypeAlignInChars(FD->getType()), | 
 |                              Context.getTypeAlignInChars( | 
 |                                  Context.getCanonicalTagType(FD->getParent()))); | 
 |         break; | 
 |       } | 
 |     } | 
 |     assert(FD && "We did not find a packed FieldDecl!"); | 
 |     Action(E, FD->getParent(), FD, Alignment); | 
 |   } | 
 | } | 
 |  | 
 | void Sema::CheckAddressOfPackedMember(Expr *rhs) { | 
 |   using namespace std::placeholders; | 
 |  | 
 |   RefersToMemberWithReducedAlignment( | 
 |       rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, | 
 |                      _2, _3, _4)); | 
 | } | 
 |  | 
 | // Performs a similar job to Sema::UsualUnaryConversions, but without any | 
 | // implicit promotion of integral/enumeration types. | 
 | static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) { | 
 |   // First, convert to an r-value. | 
 |   ExprResult Res = S.DefaultFunctionArrayLvalueConversion(E); | 
 |   if (Res.isInvalid()) | 
 |     return ExprError(); | 
 |  | 
 |   // Promote floating-point types. | 
 |   return S.UsualUnaryFPConversions(Res.get()); | 
 | } | 
 |  | 
 | bool Sema::PrepareBuiltinElementwiseMathOneArgCall( | 
 |     CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) { | 
 |   if (checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   ExprResult A = BuiltinVectorMathConversions(*this, TheCall->getArg(0)); | 
 |   if (A.isInvalid()) | 
 |     return true; | 
 |  | 
 |   TheCall->setArg(0, A.get()); | 
 |   QualType TyA = A.get()->getType(); | 
 |  | 
 |   if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, | 
 |                                   ArgTyRestr, 1)) | 
 |     return true; | 
 |  | 
 |   TheCall->setType(TyA); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinElementwiseMath(CallExpr *TheCall, | 
 |                                   EltwiseBuiltinArgTyRestriction ArgTyRestr) { | 
 |   if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) { | 
 |     TheCall->setType(*Res); | 
 |     return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) { | 
 |   std::optional<QualType> Res = BuiltinVectorMath(TheCall); | 
 |   if (!Res) | 
 |     return true; | 
 |  | 
 |   if (auto *VecTy0 = (*Res)->getAs<VectorType>()) | 
 |     TheCall->setType(VecTy0->getElementType()); | 
 |   else | 
 |     TheCall->setType(*Res); | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, | 
 |                                              SourceLocation Loc) { | 
 |   QualType L = LHS->getEnumCoercedType(S.Context), | 
 |            R = RHS->getEnumCoercedType(S.Context); | 
 |   if (L->isUnscopedEnumerationType() && R->isUnscopedEnumerationType() && | 
 |       !S.Context.hasSameUnqualifiedType(L, R)) { | 
 |     return S.Diag(Loc, diag::err_conv_mixed_enum_types) | 
 |            << LHS->getSourceRange() << RHS->getSourceRange() | 
 |            << /*Arithmetic Between*/ 0 << L << R; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | /// Check if all arguments have the same type. If the types don't match, emit an | 
 | /// error message and return true. Otherwise return false. | 
 | /// | 
 | /// For scalars we directly compare their unqualified types. But even if we | 
 | /// compare unqualified vector types, a difference in qualifiers in the element | 
 | /// types can make the vector types be considered not equal. For example, | 
 | /// vector of 4 'const float' values vs vector of 4 'float' values. | 
 | /// So we compare unqualified types of their elements and number of elements. | 
 | static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, | 
 |                                            ArrayRef<Expr *> Args) { | 
 |   assert(!Args.empty() && "Should have at least one argument."); | 
 |  | 
 |   Expr *Arg0 = Args.front(); | 
 |   QualType Ty0 = Arg0->getType(); | 
 |  | 
 |   auto EmitError = [&](Expr *ArgI) { | 
 |     SemaRef.Diag(Arg0->getBeginLoc(), | 
 |                  diag::err_typecheck_call_different_arg_types) | 
 |         << Arg0->getType() << ArgI->getType(); | 
 |   }; | 
 |  | 
 |   // Compare scalar types. | 
 |   if (!Ty0->isVectorType()) { | 
 |     for (Expr *ArgI : Args.drop_front()) | 
 |       if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) { | 
 |         EmitError(ArgI); | 
 |         return true; | 
 |       } | 
 |  | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Compare vector types. | 
 |   const auto *Vec0 = Ty0->castAs<VectorType>(); | 
 |   for (Expr *ArgI : Args.drop_front()) { | 
 |     const auto *VecI = ArgI->getType()->getAs<VectorType>(); | 
 |     if (!VecI || | 
 |         !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(), | 
 |                                                 VecI->getElementType()) || | 
 |         Vec0->getNumElements() != VecI->getNumElements()) { | 
 |       EmitError(ArgI); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | std::optional<QualType> | 
 | Sema::BuiltinVectorMath(CallExpr *TheCall, | 
 |                         EltwiseBuiltinArgTyRestriction ArgTyRestr) { | 
 |   if (checkArgCount(TheCall, 2)) | 
 |     return std::nullopt; | 
 |  | 
 |   if (checkBuiltinVectorMathMixedEnums( | 
 |           *this, TheCall->getArg(0), TheCall->getArg(1), TheCall->getExprLoc())) | 
 |     return std::nullopt; | 
 |  | 
 |   Expr *Args[2]; | 
 |   for (int I = 0; I < 2; ++I) { | 
 |     ExprResult Converted = | 
 |         BuiltinVectorMathConversions(*this, TheCall->getArg(I)); | 
 |     if (Converted.isInvalid()) | 
 |       return std::nullopt; | 
 |     Args[I] = Converted.get(); | 
 |   } | 
 |  | 
 |   SourceLocation LocA = Args[0]->getBeginLoc(); | 
 |   QualType TyA = Args[0]->getType(); | 
 |  | 
 |   if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1)) | 
 |     return std::nullopt; | 
 |  | 
 |   if (checkBuiltinVectorMathArgTypes(*this, Args)) | 
 |     return std::nullopt; | 
 |  | 
 |   TheCall->setArg(0, Args[0]); | 
 |   TheCall->setArg(1, Args[1]); | 
 |   return TyA; | 
 | } | 
 |  | 
 | bool Sema::BuiltinElementwiseTernaryMath( | 
 |     CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) { | 
 |   if (checkArgCount(TheCall, 3)) | 
 |     return true; | 
 |  | 
 |   SourceLocation Loc = TheCall->getExprLoc(); | 
 |   if (checkBuiltinVectorMathMixedEnums(*this, TheCall->getArg(0), | 
 |                                        TheCall->getArg(1), Loc) || | 
 |       checkBuiltinVectorMathMixedEnums(*this, TheCall->getArg(1), | 
 |                                        TheCall->getArg(2), Loc)) | 
 |     return true; | 
 |  | 
 |   Expr *Args[3]; | 
 |   for (int I = 0; I < 3; ++I) { | 
 |     ExprResult Converted = | 
 |         BuiltinVectorMathConversions(*this, TheCall->getArg(I)); | 
 |     if (Converted.isInvalid()) | 
 |       return true; | 
 |     Args[I] = Converted.get(); | 
 |   } | 
 |  | 
 |   int ArgOrdinal = 1; | 
 |   for (Expr *Arg : Args) { | 
 |     if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(), | 
 |                                     ArgTyRestr, ArgOrdinal++)) | 
 |       return true; | 
 |   } | 
 |  | 
 |   if (checkBuiltinVectorMathArgTypes(*this, Args)) | 
 |     return true; | 
 |  | 
 |   for (int I = 0; I < 3; ++I) | 
 |     TheCall->setArg(I, Args[I]); | 
 |  | 
 |   TheCall->setType(Args[0]->getType()); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { | 
 |   if (checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   ExprResult A = UsualUnaryConversions(TheCall->getArg(0)); | 
 |   if (A.isInvalid()) | 
 |     return true; | 
 |  | 
 |   TheCall->setArg(0, A.get()); | 
 |   return false; | 
 | } | 
 |  | 
 | bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) { | 
 |   if (checkArgCount(TheCall, 1)) | 
 |     return true; | 
 |  | 
 |   ExprResult Arg = TheCall->getArg(0); | 
 |   QualType TyArg = Arg.get()->getType(); | 
 |  | 
 |   if (!TyArg->isBuiltinType() && !TyArg->isVectorType()) | 
 |     return Diag(TheCall->getArg(0)->getBeginLoc(), | 
 |                 diag::err_builtin_invalid_arg_type) | 
 |            << 1 << /* vector */ 2 << /* integer */ 1 << /* fp */ 1 << TyArg; | 
 |  | 
 |   TheCall->setType(TyArg); | 
 |   return false; | 
 | } | 
 |  | 
 | ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall, | 
 |                                         ExprResult CallResult) { | 
 |   if (checkArgCount(TheCall, 1)) | 
 |     return ExprError(); | 
 |  | 
 |   ExprResult MatrixArg = DefaultLvalueConversion(TheCall->getArg(0)); | 
 |   if (MatrixArg.isInvalid()) | 
 |     return MatrixArg; | 
 |   Expr *Matrix = MatrixArg.get(); | 
 |  | 
 |   auto *MType = Matrix->getType()->getAs<ConstantMatrixType>(); | 
 |   if (!MType) { | 
 |     Diag(Matrix->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |         << 1 << /* matrix */ 3 << /* no int */ 0 << /* no fp */ 0 | 
 |         << Matrix->getType(); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   // Create returned matrix type by swapping rows and columns of the argument | 
 |   // matrix type. | 
 |   QualType ResultType = Context.getConstantMatrixType( | 
 |       MType->getElementType(), MType->getNumColumns(), MType->getNumRows()); | 
 |  | 
 |   // Change the return type to the type of the returned matrix. | 
 |   TheCall->setType(ResultType); | 
 |  | 
 |   // Update call argument to use the possibly converted matrix argument. | 
 |   TheCall->setArg(0, Matrix); | 
 |   return CallResult; | 
 | } | 
 |  | 
 | // Get and verify the matrix dimensions. | 
 | static std::optional<unsigned> | 
 | getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { | 
 |   std::optional<llvm::APSInt> Value = Expr->getIntegerConstantExpr(S.Context); | 
 |   if (!Value) { | 
 |     S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg) | 
 |         << Name; | 
 |     return {}; | 
 |   } | 
 |   uint64_t Dim = Value->getZExtValue(); | 
 |   if (Dim == 0 || Dim > S.Context.getLangOpts().MaxMatrixDimension) { | 
 |     S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_invalid_dimension) | 
 |         << Name << S.Context.getLangOpts().MaxMatrixDimension; | 
 |     return {}; | 
 |   } | 
 |   return Dim; | 
 | } | 
 |  | 
 | ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, | 
 |                                               ExprResult CallResult) { | 
 |   if (!getLangOpts().MatrixTypes) { | 
 |     Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled); | 
 |     return ExprError(); | 
 |   } | 
 |  | 
 |   if (checkArgCount(TheCall, 4)) | 
 |     return ExprError(); | 
 |  | 
 |   unsigned PtrArgIdx = 0; | 
 |   Expr *PtrExpr = TheCall->getArg(PtrArgIdx); | 
 |   Expr *RowsExpr = TheCall->getArg(1); | 
 |   Expr *ColumnsExpr = TheCall->getArg(2); | 
 |   Expr *StrideExpr = TheCall->getArg(3); | 
 |  | 
 |   bool ArgError = false; | 
 |  | 
 |   // Check pointer argument. | 
 |   { | 
 |     ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr); | 
 |     if (PtrConv.isInvalid()) | 
 |       return PtrConv; | 
 |     PtrExpr = PtrConv.get(); | 
 |     TheCall->setArg(0, PtrExpr); | 
 |     if (PtrExpr->isTypeDependent()) { | 
 |       TheCall->setType(Context.DependentTy); | 
 |       return TheCall; | 
 |     } | 
 |   } | 
 |  | 
 |   auto *PtrTy = PtrExpr->getType()->getAs<PointerType>(); | 
 |   QualType ElementTy; | 
 |   if (!PtrTy) { | 
 |     Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |         << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 << /* no fp */ 0 | 
 |         << PtrExpr->getType(); | 
 |     ArgError = true; | 
 |   } else { | 
 |     ElementTy = PtrTy->getPointeeType().getUnqualifiedType(); | 
 |  | 
 |     if (!ConstantMatrixType::isValidElementType(ElementTy)) { | 
 |       Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |           << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 | 
 |           << /* no fp */ 0 << PtrExpr->getType(); | 
 |       ArgError = true; | 
 |     } | 
 |   } | 
 |  | 
 |   // Apply default Lvalue conversions and convert the expression to size_t. | 
 |   auto ApplyArgumentConversions = [this](Expr *E) { | 
 |     ExprResult Conv = DefaultLvalueConversion(E); | 
 |     if (Conv.isInvalid()) | 
 |       return Conv; | 
 |  | 
 |     return tryConvertExprToType(Conv.get(), Context.getSizeType()); | 
 |   }; | 
 |  | 
 |   // Apply conversion to row and column expressions. | 
 |   ExprResult RowsConv = ApplyArgumentConversions(RowsExpr); | 
 |   if (!RowsConv.isInvalid()) { | 
 |     RowsExpr = RowsConv.get(); | 
 |     TheCall->setArg(1, RowsExpr); | 
 |   } else | 
 |     RowsExpr = nullptr; | 
 |  | 
 |   ExprResult ColumnsConv = ApplyArgumentConversions(ColumnsExpr); | 
 |   if (!ColumnsConv.isInvalid()) { | 
 |     ColumnsExpr = ColumnsConv.get(); | 
 |     TheCall->setArg(2, ColumnsExpr); | 
 |   } else | 
 |     ColumnsExpr = nullptr; | 
 |  | 
 |   // If any part of the result matrix type is still pending, just use | 
 |   // Context.DependentTy, until all parts are resolved. | 
 |   if ((RowsExpr && RowsExpr->isTypeDependent()) || | 
 |       (ColumnsExpr && ColumnsExpr->isTypeDependent())) { | 
 |     TheCall->setType(Context.DependentTy); | 
 |     return CallResult; | 
 |   } | 
 |  | 
 |   // Check row and column dimensions. | 
 |   std::optional<unsigned> MaybeRows; | 
 |   if (RowsExpr) | 
 |     MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this); | 
 |  | 
 |   std::optional<unsigned> MaybeColumns; | 
 |   if (ColumnsExpr) | 
 |     MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this); | 
 |  | 
 |   // Check stride argument. | 
 |   ExprResult StrideConv = ApplyArgumentConversions(StrideExpr); | 
 |   if (StrideConv.isInvalid()) | 
 |     return ExprError(); | 
 |   StrideExpr = StrideConv.get(); | 
 |   TheCall->setArg(3, StrideExpr); | 
 |  | 
 |   if (MaybeRows) { | 
 |     if (std::optional<llvm::APSInt> Value = | 
 |             StrideExpr->getIntegerConstantExpr(Context)) { | 
 |       uint64_t Stride = Value->getZExtValue(); | 
 |       if (Stride < *MaybeRows) { | 
 |         Diag(StrideExpr->getBeginLoc(), | 
 |              diag::err_builtin_matrix_stride_too_small); | 
 |         ArgError = true; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (ArgError || !MaybeRows || !MaybeColumns) | 
 |     return ExprError(); | 
 |  | 
 |   TheCall->setType( | 
 |       Context.getConstantMatrixType(ElementTy, *MaybeRows, *MaybeColumns)); | 
 |   return CallResult; | 
 | } | 
 |  | 
 | ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall, | 
 |                                                ExprResult CallResult) { | 
 |   if (checkArgCount(TheCall, 3)) | 
 |     return ExprError(); | 
 |  | 
 |   unsigned PtrArgIdx = 1; | 
 |   Expr *MatrixExpr = TheCall->getArg(0); | 
 |   Expr *PtrExpr = TheCall->getArg(PtrArgIdx); | 
 |   Expr *StrideExpr = TheCall->getArg(2); | 
 |  | 
 |   bool ArgError = false; | 
 |  | 
 |   { | 
 |     ExprResult MatrixConv = DefaultLvalueConversion(MatrixExpr); | 
 |     if (MatrixConv.isInvalid()) | 
 |       return MatrixConv; | 
 |     MatrixExpr = MatrixConv.get(); | 
 |     TheCall->setArg(0, MatrixExpr); | 
 |   } | 
 |   if (MatrixExpr->isTypeDependent()) { | 
 |     TheCall->setType(Context.DependentTy); | 
 |     return TheCall; | 
 |   } | 
 |  | 
 |   auto *MatrixTy = MatrixExpr->getType()->getAs<ConstantMatrixType>(); | 
 |   if (!MatrixTy) { | 
 |     Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |         << 1 << /* matrix ty */ 3 << 0 << 0 << MatrixExpr->getType(); | 
 |     ArgError = true; | 
 |   } | 
 |  | 
 |   { | 
 |     ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr); | 
 |     if (PtrConv.isInvalid()) | 
 |       return PtrConv; | 
 |     PtrExpr = PtrConv.get(); | 
 |     TheCall->setArg(1, PtrExpr); | 
 |     if (PtrExpr->isTypeDependent()) { | 
 |       TheCall->setType(Context.DependentTy); | 
 |       return TheCall; | 
 |     } | 
 |   } | 
 |  | 
 |   // Check pointer argument. | 
 |   auto *PtrTy = PtrExpr->getType()->getAs<PointerType>(); | 
 |   if (!PtrTy) { | 
 |     Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) | 
 |         << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 << 0 | 
 |         << PtrExpr->getType(); | 
 |     ArgError = true; | 
 |   } else { | 
 |     QualType ElementTy = PtrTy->getPointeeType(); | 
 |     if (ElementTy.isConstQualified()) { | 
 |       Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_store_to_const); | 
 |       ArgError = true; | 
 |     } | 
 |     ElementTy = ElementTy.getUnqualifiedType().getCanonicalType(); | 
 |     if (MatrixTy && | 
 |         !Context.hasSameType(ElementTy, MatrixTy->getElementType())) { | 
 |       Diag(PtrExpr->getBeginLoc(), | 
 |            diag::err_builtin_matrix_pointer_arg_mismatch) | 
 |           << ElementTy << MatrixTy->getElementType(); | 
 |       ArgError = true; | 
 |     } | 
 |   } | 
 |  | 
 |   // Apply default Lvalue conversions and convert the stride expression to | 
 |   // size_t. | 
 |   { | 
 |     ExprResult StrideConv = DefaultLvalueConversion(StrideExpr); | 
 |     if (StrideConv.isInvalid()) | 
 |       return StrideConv; | 
 |  | 
 |     StrideConv = tryConvertExprToType(StrideConv.get(), Context.getSizeType()); | 
 |     if (StrideConv.isInvalid()) | 
 |       return StrideConv; | 
 |     StrideExpr = StrideConv.get(); | 
 |     TheCall->setArg(2, StrideExpr); | 
 |   } | 
 |  | 
 |   // Check stride argument. | 
 |   if (MatrixTy) { | 
 |     if (std::optional<llvm::APSInt> Value = | 
 |             StrideExpr->getIntegerConstantExpr(Context)) { | 
 |       uint64_t Stride = Value->getZExtValue(); | 
 |       if (Stride < MatrixTy->getNumRows()) { | 
 |         Diag(StrideExpr->getBeginLoc(), | 
 |              diag::err_builtin_matrix_stride_too_small); | 
 |         ArgError = true; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (ArgError) | 
 |     return ExprError(); | 
 |  | 
 |   return CallResult; | 
 | } | 
 |  | 
 | void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc, | 
 |                                const NamedDecl *Callee) { | 
 |   // This warning does not make sense in code that has no runtime behavior. | 
 |   if (isUnevaluatedContext()) | 
 |     return; | 
 |  | 
 |   const NamedDecl *Caller = getCurFunctionOrMethodDecl(); | 
 |  | 
 |   if (!Caller || !Caller->hasAttr<EnforceTCBAttr>()) | 
 |     return; | 
 |  | 
 |   // Search through the enforce_tcb and enforce_tcb_leaf attributes to find | 
 |   // all TCBs the callee is a part of. | 
 |   llvm::StringSet<> CalleeTCBs; | 
 |   for (const auto *A : Callee->specific_attrs<EnforceTCBAttr>()) | 
 |     CalleeTCBs.insert(A->getTCBName()); | 
 |   for (const auto *A : Callee->specific_attrs<EnforceTCBLeafAttr>()) | 
 |     CalleeTCBs.insert(A->getTCBName()); | 
 |  | 
 |   // Go through the TCBs the caller is a part of and emit warnings if Caller | 
 |   // is in a TCB that the Callee is not. | 
 |   for (const auto *A : Caller->specific_attrs<EnforceTCBAttr>()) { | 
 |     StringRef CallerTCB = A->getTCBName(); | 
 |     if (CalleeTCBs.count(CallerTCB) == 0) { | 
 |       this->Diag(CallExprLoc, diag::warn_tcb_enforcement_violation) | 
 |           << Callee << CallerTCB; | 
 |     } | 
 |   } | 
 | } |