diff options
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 1265 |
1 files changed, 783 insertions, 482 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index b2223b755061..94070bb9c9aa 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1,4 +1,4 @@ -//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===// +//===- SemaChecking.cpp - Extra Semantic Checking -------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,34 +12,88 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.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/ExprOpenMP.h" -#include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" +#include "clang/AST/NSAPI.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" #include "clang/Analysis/Analyses/FormatString.h" +#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/Diagnostic.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/TargetBuiltins.h" +#include "clang/Basic/TargetCXXABI.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/SemaInternal.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/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/Casting.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/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <functional> +#include <limits> +#include <string> +#include <tuple> +#include <utility> using namespace clang; using namespace sema; @@ -98,6 +152,28 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { return false; } +static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { + // We need at least one argument. + if (TheCall->getNumArgs() < 1) { + S.Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) + << 0 << 1 << TheCall->getNumArgs() + << 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->getLocStart(), 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 SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { @@ -299,6 +375,41 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { return IllegalParams; } +static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { + if (!S.getOpenCLOptions().isEnabled("cl_khr_subgroups")) { + S.Diag(Call->getLocStart(), diag::err_opencl_requires_extension) + << 1 << Call->getDirectCallee() << "cl_khr_subgroups"; + return true; + } + return false; +} + +static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { + if (checkArgCount(S, TheCall, 2)) + return true; + + if (checkOpenCLSubgroupExt(S, TheCall)) + return true; + + // First argument is an ndrange_t type. + Expr *NDRangeArg = TheCall->getArg(0); + if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") { + S.Diag(NDRangeArg->getLocStart(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'ndrange_t'"; + return true; + } + + Expr *BlockArg = TheCall->getArg(1); + if (!isBlockPointer(BlockArg)) { + S.Diag(BlockArg->getLocStart(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; + return true; + } + return checkOpenCLBlockArgs(S, BlockArg); +} + /// OpenCL C v2.0, s6.13.17.6 - Check the argument to the /// get_kernel_work_group_size /// and get_kernel_preferred_work_group_size_multiple builtin functions. @@ -580,7 +691,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // OpenCL v2.0 s6.13.16.2 - The built-in read/write // functions have two forms. switch (Call->getNumArgs()) { - case 2: { + case 2: if (checkOpenCLPipeArg(S, Call)) return true; // The call with 2 arguments should be @@ -588,7 +699,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // Check packet type T. if (checkOpenCLPipePacketType(S, Call, 1)) return true; - } break; + break; case 4: { if (checkOpenCLPipeArg(S, Call)) @@ -647,6 +758,11 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { return true; } + // Since return type of reserve_read/write_pipe built-in function is + // reserve_id_t, which is not defined in the builtin def file , we used int + // as return type and need to override the return type of these functions. + Call->setType(S.Context.OCLReserveIDTy); + return false; } @@ -690,6 +806,7 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { return false; } + // \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. // \brief Performs semantic analysis for the to_global/local/private call. // \param S Reference to the semantic analyzer. @@ -721,8 +838,11 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, case Builtin::BIto_local: Qual.setAddressSpace(LangAS::opencl_local); break; + case Builtin::BIto_private: + Qual.setAddressSpace(LangAS::opencl_private); + break; default: - Qual.removeAddressSpace(); + llvm_unreachable("Invalid builtin function"); } Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( RT.getUnqualifiedType(), Qual))); @@ -770,7 +890,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, switch (Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::thumb: - if (SemaBuiltinVAStartARM(TheCall)) + if (SemaBuiltinVAStartARMMicrosoft(TheCall)) return ExprError(); break; default: @@ -839,7 +959,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (checkArgCount(*this, TheCall, 1)) return true; break; - case Builtin::BI__builtin_classify_type: if (checkArgCount(*this, TheCall, 1)) return true; TheCall->setType(Context.IntTy); @@ -959,6 +1078,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI##ID: \ return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); #include "clang/Basic/Builtins.def" + case Builtin::BI__annotation: + if (SemaBuiltinMSVCAnnotation(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_annotation: if (SemaBuiltinAnnotation(*this, TheCall)) return ExprError(); @@ -1048,22 +1171,26 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIreserve_write_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIwork_group_reserve_write_pipe: + if (SemaBuiltinReserveRWPipe(*this, TheCall)) + return ExprError(); + break; case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_write_pipe: - if (SemaBuiltinReserveRWPipe(*this, TheCall)) + if (checkOpenCLSubgroupExt(*this, TheCall) || + SemaBuiltinReserveRWPipe(*this, TheCall)) return ExprError(); - // Since return type of reserve_read/write_pipe built-in function is - // reserve_id_t, which is not defined in the builtin def file , we used int - // as return type and need to override the return type of these functions. - TheCall->setType(Context.OCLReserveIDTy); 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 (SemaBuiltinCommitRWPipe(*this, TheCall)) + return ExprError(); + break; case Builtin::BIsub_group_commit_read_pipe: case Builtin::BIsub_group_commit_write_pipe: - if (SemaBuiltinCommitRWPipe(*this, TheCall)) + if (checkOpenCLSubgroupExt(*this, TheCall) || + SemaBuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIget_pipe_num_packets: @@ -1088,11 +1215,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; + break; + case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: + case Builtin::BIget_kernel_sub_group_count_for_ndrange: + if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_os_log_format: case Builtin::BI__builtin_os_log_format_buffer_size: - if (SemaBuiltinOSLogFormat(TheCall)) { + if (SemaBuiltinOSLogFormat(TheCall)) return ExprError(); - } break; } @@ -1422,21 +1554,26 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { // For intrinsics which take an immediate value as part of the instruction, // range check them here. - unsigned i = 0, l = 0, u = 0; + // FIXME: VFP Intrinsics should error if VFP not present. switch (BuiltinID) { default: return false; - case ARM::BI__builtin_arm_ssat: i = 1; l = 1; u = 31; break; - case ARM::BI__builtin_arm_usat: i = 1; u = 31; break; + case ARM::BI__builtin_arm_ssat: + return SemaBuiltinConstantArgRange(TheCall, 1, 1, 32); + case ARM::BI__builtin_arm_usat: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + case ARM::BI__builtin_arm_ssat16: + return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + case ARM::BI__builtin_arm_usat16: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); case ARM::BI__builtin_arm_vcvtr_f: - case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break; + case ARM::BI__builtin_arm_vcvtr_d: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); case ARM::BI__builtin_arm_dmb: case ARM::BI__builtin_arm_dsb: case ARM::BI__builtin_arm_isb: - case ARM::BI__builtin_arm_dbg: l = 0; u = 15; break; + case ARM::BI__builtin_arm_dbg: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15); } - - // FIXME: VFP Intrinsics should error if VFP not present. - return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, @@ -1790,6 +1927,26 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { return false; } +/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *). +/// This checks that the target supports __builtin_cpu_is and +/// that the string argument is constant and valid. +static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) { + Expr *Arg = TheCall->getArg(0); + + // Check if the argument is a string literal. + if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) + return S.Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + + // Check the contents of the string. + StringRef Feature = + cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); + if (!S.Context.getTargetInfo().validateCpuIs(Feature)) + return S.Diag(TheCall->getLocStart(), diag::err_invalid_cpu_is) + << Arg->getSourceRange(); + return false; +} + // Check if the rounding mode is legal. bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { // Indicates if this instruction has rounding control or just SAE. @@ -2103,6 +2260,9 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); + if (BuiltinID == X86::BI__builtin_cpu_is) + return SemaBuiltinCpuIs(*this, TheCall); + // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; @@ -2209,7 +2369,10 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { i = 1; l = -128; u = 255; break; case X86::BI__builtin_ia32_vcvtps2ph: + case X86::BI__builtin_ia32_vcvtps2ph_mask: case X86::BI__builtin_ia32_vcvtps2ph256: + case X86::BI__builtin_ia32_vcvtps2ph256_mask: + case X86::BI__builtin_ia32_vcvtps2ph512_mask: case X86::BI__builtin_ia32_rndscaleps_128_mask: case X86::BI__builtin_ia32_rndscalepd_128_mask: case X86::BI__builtin_ia32_rndscaleps_256_mask: @@ -2402,6 +2565,7 @@ bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { } return false; } + /// \brief Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void @@ -2595,7 +2759,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // Type safety checking. if (FDecl) { for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) - CheckArgumentWithTypeTag(I, Args.data()); + CheckArgumentWithTypeTag(I, Args, Loc); } } @@ -2734,15 +2898,18 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { 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__atomic_load_n: case AtomicExpr::AO__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__atomic_store: case AtomicExpr::AO__atomic_store_n: return OrderingCABI != llvm::AtomicOrderingCABI::consume && @@ -2759,27 +2926,39 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); - // All these operations take one of the following forms: + // 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 } Form = Init; + + const unsigned NumForm = GNUCmpXchg + 1; const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; // where: @@ -2789,12 +2968,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // 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__c11_atomic_init == 0 && AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load, "need to update code for modified C11 atomics"); - bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init && - Op <= AtomicExpr::AO__c11_atomic_fetch_xor; + bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init && + Op <= AtomicExpr::AO__opencl_atomic_fetch_max; + bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init && + Op <= AtomicExpr::AO__c11_atomic_fetch_xor) || + IsOpenCL; bool IsN = Op == AtomicExpr::AO__atomic_load_n || Op == AtomicExpr::AO__atomic_store_n || Op == AtomicExpr::AO__atomic_exchange_n || @@ -2803,10 +2988,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, 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__atomic_load_n: Form = Load; break; @@ -2816,6 +3003,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; case AtomicExpr::AO__c11_atomic_store: + case AtomicExpr::AO__opencl_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; @@ -2823,6 +3011,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, 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__opencl_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: @@ -2832,6 +3024,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + 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: @@ -2844,6 +3039,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: Form = Xchg; break; @@ -2854,6 +3050,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: + case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: + case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: Form = C11CmpXchg; break; @@ -2863,16 +3061,19 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; } + unsigned AdjustedNumArgs = NumArgs[Form]; + if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init) + ++AdjustedNumArgs; // Check we have the right number of arguments. - if (TheCall->getNumArgs() < NumArgs[Form]) { + if (TheCall->getNumArgs() < AdjustedNumArgs) { Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << NumArgs[Form] << TheCall->getNumArgs() + << 0 << AdjustedNumArgs << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); - } else if (TheCall->getNumArgs() > NumArgs[Form]) { - Diag(TheCall->getArg(NumArgs[Form])->getLocStart(), + } else if (TheCall->getNumArgs() > AdjustedNumArgs) { + Diag(TheCall->getArg(AdjustedNumArgs)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 << NumArgs[Form] << TheCall->getNumArgs() + << 0 << AdjustedNumArgs << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); } @@ -2900,9 +3101,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (AtomTy.isConstQualified()) { + if (AtomTy.isConstQualified() || + AtomTy.getAddressSpace() == LangAS::opencl_constant) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic) - << Ptr->getType() << Ptr->getSourceRange(); + << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType() + << Ptr->getSourceRange(); return ExprError(); } ValType = AtomTy->getAs<AtomicType>()->getValueType(); @@ -2971,7 +3174,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; - if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init) + if (Form == Copy || Form == LoadCopy || Form == GNUXchg || + Form == Init) ResultType = Context.VoidTy; else if (Form == C11CmpXchg || Form == GNUCmpXchg) ResultType = Context.BoolTy; @@ -2985,7 +3189,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // 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 = 1; i != NumArgs[Form]; ++i) { + for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { @@ -3006,7 +3210,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // Treat this argument as _Nonnull as we want to show a warning if // NULL is passed into it. CheckNonNullArgument(*this, ValArg, DRE->getLocStart()); - unsigned AS = 0; + LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = ValArg->getType()->getAs<PointerType>()) { @@ -3027,7 +3231,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, break; } } else { - // The order(s) are always converted to int. + // The order(s) and scope are always converted to int. Ty = Context.IntTy; } @@ -3088,15 +3292,30 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, << SubExprs[1]->getSourceRange(); } + if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { + auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1); + llvm::APSInt Result(32); + if (Scope->isIntegerConstantExpr(Result, Context) && + !ScopeModel->isValid(Result.getZExtValue())) { + Diag(Scope->getLocStart(), diag::err_atomic_op_has_invalid_synch_scope) + << Scope->getSourceRange(); + } + SubExprs.push_back(Scope); + } + AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), SubExprs, ResultType, Op, TheCall->getRParenLoc()); if ((Op == AtomicExpr::AO__c11_atomic_load || - (Op == AtomicExpr::AO__c11_atomic_store)) && + Op == AtomicExpr::AO__c11_atomic_store || + Op == AtomicExpr::AO__opencl_atomic_load || + Op == AtomicExpr::AO__opencl_atomic_store ) && Context.AtomicUsesUnsupportedLibcall(AE)) - Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) << - ((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1); + Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) + << ((Op == AtomicExpr::AO__c11_atomic_load || + Op == AtomicExpr::AO__opencl_atomic_load) + ? 0 : 1); return AE; } @@ -3631,7 +3850,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { bool IsWindows = TT.isOSWindows(); bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; if (IsX64 || IsAArch64) { - clang::CallingConv CC = CC_C; + CallingConv CC = CC_C; if (const FunctionDecl *FD = S.getCurFunctionDecl()) CC = FD->getType()->getAs<FunctionType>()->getCallConv(); if (IsMSVAStart) { @@ -3778,7 +3997,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { +bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, // const char *named_addr); @@ -3797,23 +4016,33 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { if (checkVAStartIsInVariadicFunction(*this, Func)) return true; - const struct { - unsigned ArgNo; - QualType Type; - } ArgumentTypes[] = { - { 1, Context.getPointerType(Context.CharTy.withConst()) }, - { 2, Context.getSizeType() }, - }; - - for (const auto &AT : ArgumentTypes) { - const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens(); - if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType()) - continue; - Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible) - << Arg->getType() << AT.Type << 1 /* different class */ - << 0 /* qualifier difference */ << 3 /* parameter mismatch */ - << AT.ArgNo + 1 << Arg->getType() << AT.Type; - } + // __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() || + Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy) + Diag(Arg1->getLocStart(), 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 (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy) + Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible) + << Arg2->getType() << SizeTy + << 1 /* different class */ + << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 3 << Arg2->getType() << SizeTy; return false; } @@ -4143,9 +4372,9 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { << (unsigned)Context.getCharWidth() << Arg->getSourceRange(); - if (Result > INT32_MAX) + if (Result > std::numeric_limits<int32_t>::max()) return Diag(TheCall->getLocStart(), diag::err_alignment_too_big) - << INT32_MAX + << std::numeric_limits<int32_t>::max() << Arg->getSourceRange(); } @@ -4410,7 +4639,6 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, if (!ValidString) return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) << Arg->getSourceRange(); - } else if (IsAArch64Builtin && Fields.size() == 1) { // If the register name is one of those that appear in the condition below // and the special register builtin being used is one of the write builtins, @@ -4464,13 +4692,15 @@ bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { } namespace { + class UncoveredArgHandler { enum { Unknown = -1, AllCovered = -2 }; - signed FirstUncoveredArg; + + signed FirstUncoveredArg = Unknown; SmallVector<const Expr *, 4> DiagnosticExprs; public: - UncoveredArgHandler() : FirstUncoveredArg(Unknown) { } + UncoveredArgHandler() = default; bool hasUncoveredArg() const { return (FirstUncoveredArg >= 0); @@ -4514,7 +4744,8 @@ enum StringLiteralCheckType { SLCT_UncheckedLiteral, SLCT_CheckedLiteral }; -} // end anonymous namespace + +} // namespace static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, BinaryOperatorKind BinOpKind, @@ -4547,7 +4778,8 @@ static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, // We add an offset to a pointer here so we should support an offset as big as // possible. if (Ov) { - assert(BitWidth <= UINT_MAX / 2 && "index (intermediate) result too big"); + assert(BitWidth <= std::numeric_limits<unsigned>::max() / 2 && + "index (intermediate) result too big"); Offset = Offset.sext(2 * BitWidth); sumOffsets(Offset, Addend, BinOpKind, AddendIsRight); return; @@ -4557,6 +4789,7 @@ static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, } 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. @@ -4575,6 +4808,7 @@ class FormatStringLiteral { unsigned getByteLength() const { return FExpr->getByteLength() - getCharByteWidth() * Offset; } + unsigned getLength() const { return FExpr->getLength() - Offset; } unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); } @@ -4600,9 +4834,11 @@ class FormatStringLiteral { SourceLocation getLocStart() const LLVM_READONLY { return FExpr->getLocStart().getLocWithOffset(Offset); } + SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); } }; -} // end anonymous namespace + +} // namespace static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, @@ -4689,10 +4925,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return (CheckLeft && Left < Right) ? Left : Right; } - case Stmt::ImplicitCastExprClass: { + case Stmt::ImplicitCastExprClass: E = cast<ImplicitCastExpr>(E)->getSubExpr(); goto tryAgain; - } case Stmt::OpaqueValueExprClass: if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) { @@ -4881,7 +5116,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, case Stmt::UnaryOperatorClass: { const UnaryOperator *UnaOp = cast<UnaryOperator>(E); auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr()); - if (UnaOp->getOpcode() == clang::UO_AddrOf && ASE) { + if (UnaOp->getOpcode() == UO_AddrOf && ASE) { llvm::APSInt IndexResult; if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) { sumOffsets(Offset, IndexResult, BO_Add, /*RHS is int*/ true); @@ -5014,6 +5249,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, } namespace { + class CheckFormatHandler : public analyze_format_string::FormatStringHandler { protected: Sema &S; @@ -5027,8 +5263,8 @@ protected: ArrayRef<const Expr *> Args; unsigned FormatIdx; llvm::SmallBitVector CoveredArgs; - bool usesPositionalArgs; - bool atFirstArg; + bool usesPositionalArgs = false; + bool atFirstArg = true; bool inFunctionCall; Sema::VariadicCallType CallType; llvm::SmallBitVector &CheckedVarArgs; @@ -5046,7 +5282,6 @@ public: : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), - usesPositionalArgs(false), atFirstArg(true), inFunctionCall(inFunctionCall), CallType(callType), CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); @@ -5116,7 +5351,8 @@ protected: bool IsStringLocation, Range StringRange, ArrayRef<FixItHint> Fixit = None); }; -} // end anonymous namespace + +} // namespace SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); @@ -5470,6 +5706,7 @@ void CheckFormatHandler::EmitFormatDiagnostic( //===--- CHECK: Printf format string checking ------------------------------===// namespace { + class CheckPrintfHandler : public CheckFormatHandler { public: CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr, @@ -5534,7 +5771,8 @@ public: const char *conversionPosition) override; }; -} // end anonymous namespace + +} // namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -5652,10 +5890,6 @@ void CheckPrintfHandler::HandleIgnoredFlag( getSpecifierRange(ignoredFlag.getPosition(), 1))); } -// void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, -// bool IsStringLocation, Range StringRange, -// ArrayRef<FixItHint> Fixit = None); - void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag, unsigned flagLen) { // Warn about an empty flag. @@ -5722,7 +5956,8 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { /// 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) { - typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet; + using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>; + MethodSet Results = CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType()); for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); @@ -5737,7 +5972,7 @@ bool Sema::hasCStrMethod(const Expr *E) { // Returns true when a c_str() conversion method is found. bool CheckPrintfHandler::checkForCStrMembers( const analyze_printf::ArgType &AT, const Expr *E) { - typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet; + using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>; MethodSet Results = CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType()); @@ -5765,7 +6000,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier const char *startSpecifier, unsigned specifierLen) { using namespace analyze_format_string; - using namespace analyze_printf; + using namespace analyze_printf; + const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); if (FS.consumesDataArgument()) { @@ -6009,9 +6245,9 @@ shouldNotPrintDirectly(const ASTContext &Context, while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { StringRef Name = UserTy->getDecl()->getName(); QualType CastTy = llvm::StringSwitch<QualType>(Name) - .Case("CFIndex", Context.LongTy) - .Case("NSInteger", Context.LongTy) - .Case("NSUInteger", Context.UnsignedLongTy) + .Case("CFIndex", Context.getNSIntegerType()) + .Case("NSInteger", Context.getNSIntegerType()) + .Case("NSUInteger", Context.getNSUIntegerType()) .Case("SInt32", Context.IntTy) .Case("UInt32", Context.UnsignedIntTy) .Default(QualType()); @@ -6063,6 +6299,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, 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()); @@ -6200,7 +6437,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CastFix << ")"; SmallVector<FixItHint,4> Hints; - if (!AT.matchesType(S.Context, IntendedTy)) + if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { @@ -6315,6 +6552,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, //===--- CHECK: Scanf format string checking ------------------------------===// namespace { + class CheckScanfHandler : public CheckFormatHandler { public: CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, @@ -6341,7 +6579,8 @@ public: void HandleIncompleteScanList(const char *start, const char *end) override; }; -} // end anonymous namespace + +} // namespace void CheckScanfHandler::HandleIncompleteScanList(const char *start, const char *end) { @@ -6354,7 +6593,6 @@ bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - const analyze_scanf::ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); @@ -7041,8 +7279,8 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, if (!Size) return false; - // if E is binop and op is >, <, >=, <=, ==, &&, ||: - if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp()) + // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||: + if (!Size->isComparisonOp() && !Size->isLogicalOp()) return false; SourceRange SizeRange = Size->getSourceRange(); @@ -7096,7 +7334,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, static const Expr *getSizeOfExprArg(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType()) + if (SizeOf->getKind() == UETT_SizeOf && !SizeOf->isArgumentType()) return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); return nullptr; @@ -7106,7 +7344,7 @@ static const Expr *getSizeOfExprArg(const Expr *E) { static QualType getSizeOfArgType(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == clang::UETT_SizeOf) + if (SizeOf->getKind() == UETT_SizeOf) return SizeOf->getTypeOfArgument(); return QualType(); @@ -7294,7 +7532,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { Ex = Ex->IgnoreParenCasts(); - for (;;) { + while (true) { const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex); if (!BO || !BO->isAdditiveOp()) break; @@ -7512,7 +7750,6 @@ static const Expr *EvalAddr(const Expr *E, static void CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { - const Expr *stackE = nullptr; SmallVector<const DeclRefExpr *, 8> refVars; @@ -7997,8 +8234,7 @@ struct IntRange { bool NonNegative; IntRange(unsigned Width, bool NonNegative) - : Width(Width), NonNegative(NonNegative) - {} + : Width(Width), NonNegative(NonNegative) {} /// Returns the range of the bool type. static IntRange forBoolType() { @@ -8022,11 +8258,19 @@ struct IntRange { if (const AtomicType *AT = dyn_cast<AtomicType>(T)) T = AT->getValueType().getTypePtr(); - // For enum types, use the known bit width of the enumerators. - if (const EnumType *ET = dyn_cast<EnumType>(T)) { + if (!C.getLangOpts().CPlusPlus) { + // For enum types in C code, use the underlying datatype. + if (const EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr(); + } else if (const EnumType *ET = dyn_cast<EnumType>(T)) { + // For enum types in C++, use the known bit width of the enumerators. EnumDecl *Enum = ET->getDecl(); - if (!Enum->isCompleteDefinition()) - return IntRange(C.getIntWidth(QualType(T, 0)), false); + // 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)), + !ET->isSignedIntegerOrEnumerationType()); + } unsigned NumPositive = Enum->getNumPositiveBits(); unsigned NumNegative = Enum->getNumNegativeBits(); @@ -8080,7 +8324,10 @@ struct IntRange { } }; -IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { +} // namespace + +static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, + unsigned MaxWidth) { if (value.isSigned() && value.isNegative()) return IntRange(value.getMinSignedBits(), false); @@ -8092,8 +8339,8 @@ IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { return IntRange(value.getActiveBits(), true); } -IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, - unsigned MaxWidth) { +static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, + unsigned MaxWidth) { if (result.isInt()) return GetValueRange(C, result.getInt(), MaxWidth); @@ -8121,7 +8368,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } -QualType GetExprType(const Expr *E) { +static QualType GetExprType(const Expr *E) { QualType Ty = E->getType(); if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>()) Ty = AtomicRHS->getValueType(); @@ -8132,7 +8379,7 @@ QualType GetExprType(const Expr *E) { /// range of values it might take. /// /// \param MaxWidth - the width to which the value will be truncated -IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { +static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { E = E->IgnoreParens(); // Try a full evaluation first. @@ -8186,6 +8433,8 @@ IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { if (const auto *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { + case BO_Cmp: + llvm_unreachable("builtin <=> should have class type"); // Boolean-valued operations are single-bit and positive. case BO_LAnd: @@ -8350,16 +8599,16 @@ IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { return IntRange::forValueOfType(C, GetExprType(E)); } -IntRange GetExprRange(ASTContext &C, const Expr *E) { +static IntRange GetExprRange(ASTContext &C, const Expr *E) { return GetExprRange(C, E, C.getIntWidth(GetExprType(E))); } /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. -bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +static bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { llvm::APFloat truncated = value; bool ignored; @@ -8374,9 +8623,9 @@ bool IsSameFloatAfterCast(const llvm::APFloat &value, /// target semantics. /// /// The value might be a vector of floats (or a complex number). -bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +static bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { if (value.isFloat()) return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); @@ -8392,24 +8641,154 @@ bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); -bool IsZero(Sema &S, Expr *E) { +static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) if (isa<EnumConstantDecl>(DR->getDecl())) - return false; + return true; // Suppress cases where the '0' value is expanded from a macro. if (E->getLocStart().isMacroID()) - return false; + return true; - llvm::APSInt Value; - return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; + return false; } -bool HasEnumType(Expr *E) { +static bool isKnownToHaveUnsignedValue(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 llvm::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 llvm::None; + } + + 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 llvm::None; + } +}; +} + +static bool HasEnumType(Expr *E) { // Strip off implicit integral promotions. while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { if (ICE->getCastKind() != CK_IntegralCast && @@ -8421,40 +8800,42 @@ bool HasEnumType(Expr *E) { return E->getType()->isEnumeralType(); } -void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { - // Disable warning in template instantiations. +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; + return false; - BinaryOperatorKind op = E->getOpcode(); - if (E->isValueDependent()) - return; + Expr *OriginalOther = Other; - if (op == BO_LT && IsZero(S, E->getRHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) - << "< 0" << "false" << HasEnumType(E->getLHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BO_GE && IsZero(S, E->getRHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) - << ">= 0" << "true" << HasEnumType(E->getLHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BO_GT && IsZero(S, E->getLHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) - << "0 >" << "false" << HasEnumType(E->getRHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BO_LE && IsZero(S, E->getLHS())) { - S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) - << "0 <=" << "true" << HasEnumType(E->getRHS()) - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } -} - -void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, - Expr *Other, const llvm::APSInt &Value, - bool RhsConstant) { - // Disable warning in template instantiations. - if (S.inTemplateInstantiation()) - return; + 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; // TODO: Investigate using GetExprRange() to get tighter bounds // on the bit ranges. @@ -8462,179 +8843,32 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, if (const auto *AT = OtherT->getAs<AtomicType>()) OtherT = AT->getValueType(); IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); - unsigned OtherWidth = OtherRange.Width; - - bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue(); - - // 0 values are handled later by CheckTrivialUnsignedComparison(). - if ((Value == 0) && (!OtherIsBooleanType)) - return; - - BinaryOperatorKind op = E->getOpcode(); - bool IsTrue = true; - - // Used for diagnostic printout. - enum { - LiteralConstant = 0, - CXXBoolLiteralTrue, - CXXBoolLiteralFalse - } LiteralOrBoolConstant = LiteralConstant; - - if (!OtherIsBooleanType) { - QualType ConstantT = Constant->getType(); - QualType CommonT = E->getLHS()->getType(); - if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT)) - return; - assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) && - "comparison with non-integer type"); - - bool ConstantSigned = ConstantT->isSignedIntegerType(); - bool CommonSigned = CommonT->isSignedIntegerType(); - - bool EqualityOnly = false; - - if (CommonSigned) { - // The common type is signed, therefore no signed to unsigned conversion. - if (!OtherRange.NonNegative) { - // Check that the constant is representable in type OtherT. - if (ConstantSigned) { - if (OtherWidth >= Value.getMinSignedBits()) - return; - } else { // !ConstantSigned - if (OtherWidth >= Value.getActiveBits() + 1) - return; - } - } else { // !OtherSigned - // Check that the constant is representable in type OtherT. - // Negative values are out of range. - if (ConstantSigned) { - if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits()) - return; - } else { // !ConstantSigned - if (OtherWidth >= Value.getActiveBits()) - return; - } - } - } else { // !CommonSigned - if (OtherRange.NonNegative) { - if (OtherWidth >= Value.getActiveBits()) - return; - } else { // OtherSigned - assert(!ConstantSigned && - "Two signed types converted to unsigned types."); - // Check to see if the constant is representable in OtherT. - if (OtherWidth > Value.getActiveBits()) - return; - // Check to see if the constant is equivalent to a negative value - // cast to CommonT. - if (S.Context.getIntWidth(ConstantT) == - S.Context.getIntWidth(CommonT) && - Value.isNegative() && Value.getMinSignedBits() <= OtherWidth) - return; - // The constant value rests between values that OtherT can represent - // after conversion. Relational comparison still works, but equality - // comparisons will be tautological. - EqualityOnly = true; - } - } - - bool PositiveConstant = !ConstantSigned || Value.isNonNegative(); - - if (op == BO_EQ || op == BO_NE) { - IsTrue = op == BO_NE; - } else if (EqualityOnly) { - return; - } else if (RhsConstant) { - if (op == BO_GT || op == BO_GE) - IsTrue = !PositiveConstant; - else // op == BO_LT || op == BO_LE - IsTrue = PositiveConstant; - } else { - if (op == BO_LT || op == BO_LE) - IsTrue = !PositiveConstant; - else // op == BO_GT || op == BO_GE - IsTrue = PositiveConstant; - } - } else { - // Other isKnownToHaveBooleanValue - enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn }; - enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal }; - enum ConstantSide { Lhs, Rhs, SizeOfConstSides }; - - static const struct LinkedConditions { - CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal]; - CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal]; - - } TruthTable = { - // Constant on LHS. | Constant on RHS. | - // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One| - { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } }, - { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } }, - { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } }, - { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } }, - { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } }, - { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } } - }; - - bool ConstantIsBoolLiteral = isa<CXXBoolLiteralExpr>(Constant); - - enum ConstantValue ConstVal = Zero; - if (Value.isUnsigned() || Value.isNonNegative()) { - if (Value == 0) { - LiteralOrBoolConstant = - ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant; - ConstVal = Zero; - } else if (Value == 1) { - LiteralOrBoolConstant = - ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant; - ConstVal = One; - } else { - LiteralOrBoolConstant = LiteralConstant; - ConstVal = GT_One; - } - } else { - ConstVal = LT_Zero; - } - - CompareBoolWithConstantResult CmpRes; - - switch (op) { - case BO_LT: - CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal]; - break; - case BO_GT: - CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal]; - break; - case BO_LE: - CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal]; - break; - case BO_GE: - CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal]; - break; - case BO_EQ: - CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal]; - break; - case BO_NE: - CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal]; - break; - default: - CmpRes = Unkwn; - break; - } + // 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) + OtherRange = IntRange::forBoolType(); + + // Determine the promoted range of the other type and see if a comparison of + // the constant against that range is tautological. + PromotedRange OtherPromotedRange(OtherRange, Value.getBitWidth(), + Value.isUnsigned()); + auto Cmp = OtherPromotedRange.compare(Value); + auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant); + if (!Result) + return false; - if (CmpRes == AFals) { - IsTrue = false; - } else if (CmpRes == ATrue) { - IsTrue = true; - } else { - return; - } - } + // 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; // If this is a comparison to an enum constant, include that // constant in the diagnostic. @@ -8642,6 +8876,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, if (const DeclRefExpr *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) @@ -8649,17 +8884,35 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, else OS << Value; - S.DiagRuntimeBehavior( - E->getOperatorLoc(), E, - S.PDiag(diag::warn_out_of_range_compare) - << OS.str() << LiteralOrBoolConstant - << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); + // 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 { + unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) + ? (HasEnumType(OriginalOther) + ? diag::warn_unsigned_enum_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. -void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { +static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } @@ -8667,7 +8920,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { /// \brief Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings -void AnalyzeComparison(Sema &S, BinaryOperator *E) { +static void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); @@ -8680,39 +8933,45 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { if (E->isValueDependent()) return AnalyzeImpConvsInComparison(S, E); - Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); - Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); - - bool IsComparisonConstant = false; - - // Check whether an integer constant comparison results in a value - // of 'true' or 'false'. + Expr *LHS = E->getLHS(); + Expr *RHS = E->getRHS(); + if (T->isIntegralType(S.Context)) { llvm::APSInt RHSValue; - bool IsRHSIntegralLiteral = - RHS->isIntegerConstantExpr(RHSValue, S.Context); llvm::APSInt LHSValue; - bool IsLHSIntegralLiteral = - LHS->isIntegerConstantExpr(LHSValue, S.Context); - if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral) - DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true); - else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral) - DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false); - else - IsComparisonConstant = - (IsRHSIntegralLiteral && IsLHSIntegralLiteral); - } else if (!T->hasUnsignedIntegerRepresentation()) - IsComparisonConstant = E->isIntegerConstantExpr(S.Context); - - // 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. - // - // We also don't care about value-dependent expressions or expressions - // whose result is a constant. - if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant) + + bool IsRHSIntegralLiteral = RHS->isIntegerConstantExpr(RHSValue, S.Context); + bool IsLHSIntegralLiteral = LHS->isIntegerConstantExpr(LHSValue, S.Context); + + // We don't care about expressions whose result is a constant. + if (IsRHSIntegralLiteral && IsLHSIntegralLiteral) + return AnalyzeImpConvsInComparison(S, E); + + // We only care about expressions where just one side is literal + if (IsRHSIntegralLiteral ^ IsLHSIntegralLiteral) { + // Is the constant on the RHS or LHS? + const bool RhsConstant = IsRHSIntegralLiteral; + 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(); + // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; @@ -8725,7 +8984,6 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { signedOperand = RHS; unsignedOperand = LHS; } else { - CheckTrivialUnsignedComparison(S, E); return AnalyzeImpConvsInComparison(S, E); } @@ -8737,11 +8995,9 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc()); AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); - // If the signed range is non-negative, -Wsign-compare won't fire, - // but we should still check for comparisons which are always true - // or false. + // If the signed range is non-negative, -Wsign-compare won't fire. if (signedRange.NonNegative) - return CheckTrivialUnsignedComparison(S, E); + return; // For (in)equality comparisons, if the unsigned operand is a // constant which cannot collide with a overflowed signed operand, @@ -8768,8 +9024,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { /// Analyzes an attempt to assign the given value to a bitfield. /// /// Returns true if there was something fishy about the attempt. -bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, - SourceLocation InitLoc) { +static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, + SourceLocation InitLoc) { assert(Bitfield->isBitField()); if (Bitfield->isInvalidDecl()) return false; @@ -8899,7 +9155,7 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, /// Analyze the given simple or compound assignment for warning-worthy /// operations. -void AnalyzeAssignment(Sema &S, BinaryOperator *E) { +static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // Just recurse on the LHS. AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); @@ -8918,9 +9174,9 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, - SourceLocation CContext, unsigned diag, - bool pruneControlFlow = false) { +static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, + SourceLocation CContext, unsigned diag, + bool pruneControlFlow = false) { if (pruneControlFlow) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag) @@ -8933,16 +9189,16 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, - unsigned diag, bool pruneControlFlow = false) { +static void DiagnoseImpCast(Sema &S, 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. -void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, - - SourceLocation CContext) { +static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, + SourceLocation CContext) { const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); const bool PruneWarnings = S.inTemplateInstantiation(); @@ -9032,7 +9288,8 @@ void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, } } -std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { +static std::string PrettyPrintInRange(const llvm::APSInt &Value, + IntRange Range) { if (!Range.Width) return "0"; llvm::APSInt ValueInRange = Value; @@ -9041,7 +9298,7 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { return ValueInRange.toString(10); } -bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { +static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { if (!isa<ImplicitCastExpr>(Ex)) return false; @@ -9060,8 +9317,8 @@ bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { FloatCandidateBT && (FloatCandidateBT->isFloatingPoint())); } -void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, - SourceLocation CC) { +static void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, + SourceLocation CC) { unsigned NumArgs = TheCall->getNumArgs(); for (unsigned i = 0; i < NumArgs; ++i) { Expr *CurrA = TheCall->getArg(i); @@ -9081,7 +9338,8 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, } } -void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { +static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC) { if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, E->getExprLoc())) return; @@ -9125,20 +9383,24 @@ void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { return; S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) - << (NullKind == Expr::NPCK_CXX11_nullptr) << T << clang::SourceRange(CC) + << (NullKind == Expr::NPCK_CXX11_nullptr) << T << SourceRange(CC) << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T, Loc)); } -void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral); -void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral); +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral); + +static void +checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); /// Check a single element within a collection literal against the /// target element type. -void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, - Expr *Element, unsigned ElementKind) { +static void checkObjCCollectionLiteralElement(Sema &S, + QualType TargetElementType, + Expr *Element, + unsigned ElementKind) { // Skip a bitcast to 'id' or qualified 'id'. if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) { if (ICE->getCastKind() == CK_BitCast && @@ -9167,8 +9429,8 @@ void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, /// Check an Objective-C array literal being converted to the given /// target type. -void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral) { +static void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { if (!S.NSArrayDecl) return; @@ -9195,8 +9457,9 @@ void checkObjCArrayLiteral(Sema &S, QualType TargetType, /// Check an Objective-C dictionary literal being converted to the given /// target type. -void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral) { +static void +checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral) { if (!S.NSDictionaryDecl) return; @@ -9224,8 +9487,8 @@ void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, // Helper function to filter out cases for constant width constant conversion. // Don't warn on char array initialization or for non-decimal values. -bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC) { +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. @@ -9248,8 +9511,9 @@ bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, return true; } -void CheckImplicitConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC, bool *ICContext = nullptr) { +static void +CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, + bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); @@ -9316,10 +9580,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip complex types. if (isa<ComplexType>(Source)) { if (!isa<ComplexType>(Target)) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (S.SourceMgr.isInSystemMacro(CC) || Target->isBooleanType()) return; - return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar); + return DiagnoseImpCast(S, E, T, CC, + S.getLangOpts().CPlusPlus + ? diag::err_impcast_complex_scalar + : diag::warn_impcast_complex_scalar); } Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); @@ -9514,11 +9781,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } -void CheckConditionalOperator(Sema &S, ConditionalOperator *E, - SourceLocation CC, QualType T); +static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, + SourceLocation CC, QualType T); -void CheckConditionalOperand(Sema &S, Expr *E, QualType T, - SourceLocation CC, bool &ICContext) { +static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, + SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); if (isa<ConditionalOperator>(E)) @@ -9529,8 +9796,8 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T, return CheckImplicitConversion(S, E, T, CC, &ICContext); } -void CheckConditionalOperator(Sema &S, ConditionalOperator *E, - SourceLocation CC, QualType T) { +static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, + SourceLocation CC, QualType T) { AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); bool Suspicious = false; @@ -9559,7 +9826,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, /// CheckBoolLikeConversion - Check conversion of given expression to boolean. /// Input argument E is a logical expression. -void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { +static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { if (S.getLangOpts().Bool) return; CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); @@ -9568,7 +9835,8 @@ void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. -void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { +static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, + SourceLocation CC) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); @@ -9661,8 +9929,6 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } -} // end anonymous namespace - /// Diagnose integer type and any valid implicit convertion to it. static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { // Taking into account implicit conversions, @@ -9968,10 +10234,11 @@ void Sema::CheckForIntOverflow (Expr *E) { } namespace { + /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { - typedef EvaluatedExprVisitor<SequenceChecker> Base; + using Base = EvaluatedExprVisitor<SequenceChecker>; /// \brief 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 @@ -9990,11 +10257,14 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { /// \brief A region within an expression which may be sequenced with respect /// to some other region. class Seq { - explicit Seq(unsigned N) : Index(N) {} - unsigned Index; friend class SequenceTree; + + unsigned Index = 0; + + explicit Seq(unsigned N) : Index(N) {} + public: - Seq() : Index(0) {} + Seq() = default; }; SequenceTree() { Values.push_back(Value(0)); } @@ -10038,16 +10308,18 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; /// An object for which we can track unsequenced uses. - typedef NamedDecl *Object; + using Object = 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, @@ -10056,29 +10328,37 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; struct Usage { - Usage() : Use(nullptr), Seq() {} - Expr *Use; + Expr *Use = nullptr; SequenceTree::Seq Seq; + + Usage() = default; }; struct UsageInfo { - UsageInfo() : Diagnosed(false) {} Usage Uses[UK_Count]; + /// Have we issued a diagnostic for this variable already? - bool Diagnosed; + bool Diagnosed = false; + + UsageInfo() = default; }; - typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap; + 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; + SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr; + /// Expressions to check later. We defer checking these to reduce /// stack usage. SmallVectorImpl<Expr *> &WorkList; @@ -10093,6 +10373,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) { Self.ModAsSideEffect = &ModAsSideEffect; } + ~SequencedSubexpression() { for (auto &M : llvm::reverse(ModAsSideEffect)) { UsageInfo &U = Self.UsageMap[M.first]; @@ -10105,7 +10386,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SequenceChecker &Self; SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect; - SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect; + SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect; }; /// RAII object wrapping the visitation of a subexpression which we might @@ -10115,9 +10396,10 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { class EvaluationTracker { public: EvaluationTracker(SequenceChecker &Self) - : Self(Self), Prev(Self.EvalTracker), EvalOK(true) { + : Self(Self), Prev(Self.EvalTracker) { Self.EvalTracker = this; } + ~EvaluationTracker() { Self.EvalTracker = Prev; if (Prev) @@ -10134,8 +10416,8 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { private: SequenceChecker &Self; EvaluationTracker *Prev; - bool EvalOK; - } *EvalTracker; + bool EvalOK = true; + } *EvalTracker = nullptr; /// \brief Find the object which is produced by the specified expression, /// if any. @@ -10169,6 +10451,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { U.Seq = Region; } } + /// \brief Check whether a modification or use conflicts with a prior usage. void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, bool IsModMod) { @@ -10196,6 +10479,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { // Uses conflict with other modifications. checkUsage(O, U, Use, UK_ModAsValue, false); } + void notePostUse(Object O, Expr *Use) { UsageInfo &U = UsageMap[O]; checkUsage(O, U, Use, UK_ModAsSideEffect, false); @@ -10208,6 +10492,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { checkUsage(O, U, Mod, UK_ModAsValue, true); checkUsage(O, U, Mod, UK_Use, false); } + void notePostMod(Object O, Expr *Use, UsageKind UK) { UsageInfo &U = UsageMap[O]; checkUsage(O, U, Use, UK_ModAsSideEffect, true); @@ -10216,8 +10501,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { public: SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList) - : Base(S.Context), SemaRef(S), Region(Tree.root()), - ModAsSideEffect(nullptr), WorkList(WorkList), EvalTracker(nullptr) { + : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) { Visit(E); } @@ -10451,7 +10735,8 @@ public: Tree.merge(Elts[I]); } }; -} // end anonymous namespace + +} // namespace void Sema::CheckUnsequencedOperations(Expr *E) { SmallVector<Expr *, 8> WorkList; @@ -10868,19 +11153,22 @@ void Sema::CheckArrayAccess(const Expr *expr) { //===--- CHECK: Objective-C retain cycles ----------------------------------// namespace { - struct RetainCycleOwner { - RetainCycleOwner() : Variable(nullptr), Indirect(false) {} - VarDecl *Variable; - SourceRange Range; - SourceLocation Loc; - bool Indirect; - void setLocsFrom(Expr *e) { - Loc = e->getExprLoc(); - Range = e->getSourceRange(); - } - }; -} // end anonymous namespace +struct RetainCycleOwner { + VarDecl *Variable = nullptr; + SourceRange Range; + SourceLocation Loc; + bool Indirect = false; + + RetainCycleOwner() = default; + + void setLocsFrom(Expr *e) { + Loc = e->getExprLoc(); + Range = e->getSourceRange(); + } +}; + +} // namespace /// Consider whether capturing the given variable can possibly lead to /// a retain cycle. @@ -10977,15 +11265,16 @@ static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) { } namespace { + struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> { - FindCaptureVisitor(ASTContext &Context, VarDecl *variable) - : EvaluatedExprVisitor<FindCaptureVisitor>(Context), - Context(Context), Variable(variable), Capturer(nullptr), - VarWillBeReased(false) {} ASTContext &Context; VarDecl *Variable; - Expr *Capturer; - bool VarWillBeReased; + Expr *Capturer = nullptr; + bool VarWillBeReased = false; + + FindCaptureVisitor(ASTContext &Context, VarDecl *variable) + : EvaluatedExprVisitor<FindCaptureVisitor>(Context), + Context(Context), Variable(variable) {} void VisitDeclRefExpr(DeclRefExpr *ref) { if (ref->getDecl() == Variable && !Capturer) @@ -11010,6 +11299,7 @@ namespace { if (OVE->getSourceExpr()) Visit(OVE->getSourceExpr()); } + void VisitBinaryOperator(BinaryOperator *BinOp) { if (!Variable || VarWillBeReased || BinOp->getOpcode() != BO_Assign) return; @@ -11026,7 +11316,8 @@ namespace { } } }; -} // end anonymous namespace + +} // namespace /// Check whether the given argument is a block which captures a /// variable. @@ -11283,9 +11574,15 @@ void Sema::checkRetainCycles(ObjCMessageExpr *msg) { } // Check whether the receiver is captured by any of the arguments. - for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) - if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) + const ObjCMethodDecl *MD = msg->getMethodDecl(); + for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) { + if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) { + // noescape blocks should not be retained by the method. + if (MD && MD->parameters()[i]->hasAttr<NoEscapeAttr>()) + continue; return diagnoseRetainCycle(*this, capturer, owner); + } + } } /// Check a property assign to see if it's likely to cause a retain cycle. @@ -11433,16 +11730,14 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, //===--- CHECK: Empty statement body (-Wempty-body) ---------------------===// -namespace { -bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, - SourceLocation StmtLoc, - const NullStmt *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; @@ -11465,7 +11760,6 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, return true; } -} // end anonymous namespace void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, @@ -11577,9 +11871,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, return; // Check for a call to std::move - const FunctionDecl *FD = CE->getDirectCallee(); - if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || - !FD->getIdentifier()->isStr("move")) + if (!CE->isCallToStdMove()) return; // Get argument from std::move @@ -11647,12 +11939,10 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, //===--- Layout compatibility ----------------------------------------------// -namespace { - -bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); +static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); /// \brief Check if two enumeration types are layout-compatible. -bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { +static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { // C++11 [dcl.enum] p8: // Two enumeration types are layout-compatible if they have the same // underlying type. @@ -11661,7 +11951,8 @@ bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { } /// \brief Check if two fields are layout-compatible. -bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { +static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, + FieldDecl *Field2) { if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) return false; @@ -11682,9 +11973,8 @@ bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { /// \brief Check if two standard-layout structs are layout-compatible. /// (C++11 [class.mem] p17) -bool isLayoutCompatibleStruct(ASTContext &C, - RecordDecl *RD1, - RecordDecl *RD2) { +static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, + RecordDecl *RD2) { // If both records are C++ classes, check that base classes match. if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1)) { // If one of records is a CXXRecordDecl we are in C++ mode, @@ -11727,9 +12017,8 @@ bool isLayoutCompatibleStruct(ASTContext &C, /// \brief Check if two standard-layout unions are layout-compatible. /// (C++11 [class.mem] p18) -bool isLayoutCompatibleUnion(ASTContext &C, - RecordDecl *RD1, - RecordDecl *RD2) { +static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, + RecordDecl *RD2) { llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields; for (auto *Field2 : RD2->fields()) UnmatchedFields.insert(Field2); @@ -11754,7 +12043,8 @@ bool isLayoutCompatibleUnion(ASTContext &C, return UnmatchedFields.empty(); } -bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { +static bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, + RecordDecl *RD2) { if (RD1->isUnion() != RD2->isUnion()) return false; @@ -11765,7 +12055,7 @@ bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { } /// \brief Check if two types are layout-compatible in C++11 sense. -bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { +static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { if (T1.isNull() || T2.isNull()) return false; @@ -11799,11 +12089,9 @@ bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { return false; } -} // end anonymous namespace //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// -namespace { /// \brief Given a type tag expression find the type tag itself. /// /// \param TypeExpr Type tag expression, as it appears in user's code. @@ -11811,8 +12099,8 @@ namespace { /// \param VD Declaration of an identifier that appears in a type tag. /// /// \param MagicValue Type tag magic value. -bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, - const ValueDecl **VD, uint64_t *MagicValue) { +static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, + const ValueDecl **VD, uint64_t *MagicValue) { while(true) { if (!TypeExpr) return false; @@ -11887,7 +12175,7 @@ bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, /// \param TypeInfo Information about the corresponding C type. /// /// \returns true if the corresponding C type was found. -bool GetMatchingCType( +static bool GetMatchingCType( const IdentifierInfo *ArgumentKind, const Expr *TypeExpr, const ASTContext &Ctx, const llvm::DenseMap<Sema::TypeTagMagicValue, @@ -11930,7 +12218,6 @@ bool GetMatchingCType( TypeInfo = I->second; return true; } -} // end anonymous namespace void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, @@ -11945,8 +12232,7 @@ void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, TypeTagData(Type, LayoutCompatible, MustBeNull); } -namespace { -bool IsSameCharType(QualType T1, QualType T2) { +static bool IsSameCharType(QualType T1, QualType T2) { const BuiltinType *BT1 = T1->getAs<BuiltinType>(); if (!BT1) return false; @@ -11963,13 +12249,20 @@ bool IsSameCharType(QualType T1, QualType T2) { (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); } -} // end anonymous namespace void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, - const Expr * const *ExprArgs) { + const ArrayRef<const Expr *> ExprArgs, + SourceLocation CallSiteLoc) { const IdentifierInfo *ArgumentKind = Attr->getArgumentKind(); bool IsPointerAttr = Attr->getIsPointer(); + // Retrieve the argument representing the 'type_tag'. + if (Attr->getTypeTagIdx() >= ExprArgs.size()) { + // Add 1 to display the user's specified value. + Diag(CallSiteLoc, diag::err_tag_index_out_of_range) + << 0 << Attr->getTypeTagIdx() + 1; + return; + } const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; bool FoundWrongKind; TypeTagData TypeInfo; @@ -11983,6 +12276,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, return; } + // Retrieve the argument representing the 'arg_idx'. + if (Attr->getArgumentIdx() >= ExprArgs.size()) { + // Add 1 to display the user's specified value. + Diag(CallSiteLoc, diag::err_tag_index_out_of_range) + << 1 << Attr->getArgumentIdx() + 1; + return; + } const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). @@ -12074,8 +12374,9 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { MisalignedMember(Op)); if (MA != MisalignedMembers.end() && (T->isIntegerType() || - (T->isPointerType() && - Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment))) + (T->isPointerType() && (T->getPointeeType()->isIncompleteType() || + Context.getTypeAlignInChars( + T->getPointeeType()) <= MA->Alignment)))) MisalignedMembers.erase(MA); } } @@ -12192,8 +12493,8 @@ void Sema::RefersToMemberWithReducedAlignment( void Sema::CheckAddressOfPackedMember(Expr *rhs) { using namespace std::placeholders; + RefersToMemberWithReducedAlignment( rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, _2, _3, _4)); } - |