aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r--lib/Sema/SemaChecking.cpp1265
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));
}
-