diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:18:08 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:18:08 +0000 |
commit | bab175ec4b075c8076ba14c762900392533f6ee4 (patch) | |
tree | 01f4f29419a2cb10abe13c1e63cd2a66068b0137 /lib/Sema/SemaChecking.cpp | |
parent | 8b7a8012d223fac5d17d16a66bb39168a9a1dfc0 (diff) |
Notes
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 1250 |
1 files changed, 1025 insertions, 225 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7f7dbe8873d4e..9c902959233fd 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" @@ -33,14 +32,14 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Format.h" #include "llvm/Support/Locale.h" -#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" -#include <limits> using namespace clang; using namespace sema; @@ -316,8 +315,18 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { return checkOpenCLBlockArgs(S, BlockArg); } +/// Diagnose integer type and any valid implicit convertion to it. +static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, + const QualType &IntType); + static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, - unsigned Start, unsigned End); + unsigned Start, unsigned End) { + bool IllegalParams = false; + for (unsigned I = Start; I <= End; ++I) + IllegalParams |= checkOpenCLEnqueueIntType(S, TheCall->getArg(I), + S.Context.getSizeType()); + return IllegalParams; +} /// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all /// 'local void*' parameter of passed block. @@ -452,16 +461,20 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { Expr *Arg4 = TheCall->getArg(4); Expr *Arg5 = TheCall->getArg(5); - // Fith argument is always passed as pointers to clk_event_t. - if (!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { + // Fifth argument is always passed as a pointer to clk_event_t. + if (!Arg4->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNotNull) && + !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { S.Diag(TheCall->getArg(4)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } - // Sixth argument is always passed as pointers to clk_event_t. - if (!(Arg5->getType()->isPointerType() && + // Sixth argument is always passed as a pointer to clk_event_t. + if (!Arg5->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNotNull) && + !(Arg5->getType()->isPointerType() && Arg5->getType()->getPointeeType()->isClkEventT())) { S.Diag(TheCall->getArg(5)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) @@ -792,6 +805,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinPrefetch(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_alloca_with_align: + if (SemaBuiltinAllocaWithAlign(TheCall)) + return ExprError(); + break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: if (SemaBuiltinAssume(TheCall)) @@ -1021,6 +1038,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // check for the argument. if (SemaBuiltinRWPipe(*this, TheCall)) return ExprError(); + TheCall->setType(Context.IntTy); break; case Builtin::BIreserve_read_pipe: case Builtin::BIreserve_write_pipe: @@ -1048,6 +1066,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIget_pipe_max_packets: if (SemaBuiltinPipePackets(*this, TheCall)) return ExprError(); + TheCall->setType(Context.UnsignedIntTy); break; case Builtin::BIto_global: case Builtin::BIto_local: @@ -1064,6 +1083,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIget_kernel_preferred_work_group_size_multiple: if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); + break; + case Builtin::BI__builtin_os_log_format: + case Builtin::BI__builtin_os_log_format_buffer_size: + if (SemaBuiltinOSLogFormat(TheCall)) { + return ExprError(); + } + break; } // Since the target specific builtins for each arch overlap, only check those @@ -1757,51 +1783,237 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { return false; } -bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - int i = 0, l = 0, u = 0; +// Check if the rounding mode is legal. +bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { + // Indicates if this instruction has rounding control or just SAE. + bool HasRC = false; + + unsigned ArgNum = 0; switch (BuiltinID) { default: return false; - case X86::BI__builtin_cpu_supports: + case X86::BI__builtin_ia32_vcvttsd2si32: + case X86::BI__builtin_ia32_vcvttsd2si64: + case X86::BI__builtin_ia32_vcvttsd2usi32: + case X86::BI__builtin_ia32_vcvttsd2usi64: + case X86::BI__builtin_ia32_vcvttss2si32: + case X86::BI__builtin_ia32_vcvttss2si64: + case X86::BI__builtin_ia32_vcvttss2usi32: + case X86::BI__builtin_ia32_vcvttss2usi64: + ArgNum = 1; + break; + case X86::BI__builtin_ia32_cvtps2pd512_mask: + case X86::BI__builtin_ia32_cvttpd2dq512_mask: + case X86::BI__builtin_ia32_cvttpd2qq512_mask: + case X86::BI__builtin_ia32_cvttpd2udq512_mask: + case X86::BI__builtin_ia32_cvttpd2uqq512_mask: + case X86::BI__builtin_ia32_cvttps2dq512_mask: + case X86::BI__builtin_ia32_cvttps2qq512_mask: + case X86::BI__builtin_ia32_cvttps2udq512_mask: + case X86::BI__builtin_ia32_cvttps2uqq512_mask: + case X86::BI__builtin_ia32_exp2pd_mask: + case X86::BI__builtin_ia32_exp2ps_mask: + case X86::BI__builtin_ia32_getexppd512_mask: + case X86::BI__builtin_ia32_getexpps512_mask: + case X86::BI__builtin_ia32_rcp28pd_mask: + case X86::BI__builtin_ia32_rcp28ps_mask: + case X86::BI__builtin_ia32_rsqrt28pd_mask: + case X86::BI__builtin_ia32_rsqrt28ps_mask: + case X86::BI__builtin_ia32_vcomisd: + case X86::BI__builtin_ia32_vcomiss: + case X86::BI__builtin_ia32_vcvtph2ps512_mask: + ArgNum = 3; + break; + case X86::BI__builtin_ia32_cmppd512_mask: + case X86::BI__builtin_ia32_cmpps512_mask: + case X86::BI__builtin_ia32_cmpsd_mask: + case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_cvtss2sd_round_mask: + case X86::BI__builtin_ia32_getexpsd128_round_mask: + case X86::BI__builtin_ia32_getexpss128_round_mask: + case X86::BI__builtin_ia32_maxpd512_mask: + case X86::BI__builtin_ia32_maxps512_mask: + case X86::BI__builtin_ia32_maxsd_round_mask: + case X86::BI__builtin_ia32_maxss_round_mask: + case X86::BI__builtin_ia32_minpd512_mask: + case X86::BI__builtin_ia32_minps512_mask: + case X86::BI__builtin_ia32_minsd_round_mask: + case X86::BI__builtin_ia32_minss_round_mask: + case X86::BI__builtin_ia32_rcp28sd_round_mask: + case X86::BI__builtin_ia32_rcp28ss_round_mask: + case X86::BI__builtin_ia32_reducepd512_mask: + case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rsqrt28sd_round_mask: + case X86::BI__builtin_ia32_rsqrt28ss_round_mask: + ArgNum = 4; + break; + case X86::BI__builtin_ia32_fixupimmpd512_mask: + case X86::BI__builtin_ia32_fixupimmpd512_maskz: + case X86::BI__builtin_ia32_fixupimmps512_mask: + case X86::BI__builtin_ia32_fixupimmps512_maskz: + case X86::BI__builtin_ia32_fixupimmsd_mask: + case X86::BI__builtin_ia32_fixupimmsd_maskz: + case X86::BI__builtin_ia32_fixupimmss_mask: + case X86::BI__builtin_ia32_fixupimmss_maskz: + case X86::BI__builtin_ia32_rangepd512_mask: + case X86::BI__builtin_ia32_rangeps512_mask: + case X86::BI__builtin_ia32_rangesd128_round_mask: + case X86::BI__builtin_ia32_rangess128_round_mask: + case X86::BI__builtin_ia32_reducesd_mask: + case X86::BI__builtin_ia32_reducess_mask: + case X86::BI__builtin_ia32_rndscalesd_round_mask: + case X86::BI__builtin_ia32_rndscaless_round_mask: + ArgNum = 5; + break; + case X86::BI__builtin_ia32_vcvtsd2si64: + case X86::BI__builtin_ia32_vcvtsd2si32: + case X86::BI__builtin_ia32_vcvtsd2usi32: + case X86::BI__builtin_ia32_vcvtsd2usi64: + case X86::BI__builtin_ia32_vcvtss2si32: + case X86::BI__builtin_ia32_vcvtss2si64: + case X86::BI__builtin_ia32_vcvtss2usi32: + case X86::BI__builtin_ia32_vcvtss2usi64: + ArgNum = 1; + HasRC = true; + break; + case X86::BI__builtin_ia32_cvtsi2sd64: + case X86::BI__builtin_ia32_cvtsi2ss32: + case X86::BI__builtin_ia32_cvtsi2ss64: + case X86::BI__builtin_ia32_cvtusi2sd64: + case X86::BI__builtin_ia32_cvtusi2ss32: + case X86::BI__builtin_ia32_cvtusi2ss64: + ArgNum = 2; + HasRC = true; + break; + case X86::BI__builtin_ia32_cvtdq2ps512_mask: + case X86::BI__builtin_ia32_cvtudq2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2qq512_mask: + case X86::BI__builtin_ia32_cvtpd2uqq512_mask: + case X86::BI__builtin_ia32_cvtps2qq512_mask: + case X86::BI__builtin_ia32_cvtps2uqq512_mask: + case X86::BI__builtin_ia32_cvtqq2pd512_mask: + case X86::BI__builtin_ia32_cvtqq2ps512_mask: + case X86::BI__builtin_ia32_cvtuqq2pd512_mask: + case X86::BI__builtin_ia32_cvtuqq2ps512_mask: + case X86::BI__builtin_ia32_sqrtpd512_mask: + case X86::BI__builtin_ia32_sqrtps512_mask: + ArgNum = 3; + HasRC = true; + break; + case X86::BI__builtin_ia32_addpd512_mask: + case X86::BI__builtin_ia32_addps512_mask: + case X86::BI__builtin_ia32_divpd512_mask: + case X86::BI__builtin_ia32_divps512_mask: + case X86::BI__builtin_ia32_mulpd512_mask: + case X86::BI__builtin_ia32_mulps512_mask: + case X86::BI__builtin_ia32_subpd512_mask: + case X86::BI__builtin_ia32_subps512_mask: + case X86::BI__builtin_ia32_addss_round_mask: + case X86::BI__builtin_ia32_addsd_round_mask: + case X86::BI__builtin_ia32_divss_round_mask: + case X86::BI__builtin_ia32_divsd_round_mask: + case X86::BI__builtin_ia32_mulss_round_mask: + case X86::BI__builtin_ia32_mulsd_round_mask: + case X86::BI__builtin_ia32_subss_round_mask: + case X86::BI__builtin_ia32_subsd_round_mask: + case X86::BI__builtin_ia32_scalefpd512_mask: + case X86::BI__builtin_ia32_scalefps512_mask: + case X86::BI__builtin_ia32_scalefsd_round_mask: + case X86::BI__builtin_ia32_scalefss_round_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_cvtsd2ss_round_mask: + case X86::BI__builtin_ia32_sqrtsd_round_mask: + case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_vfmaddpd512_mask: + case X86::BI__builtin_ia32_vfmaddpd512_mask3: + case X86::BI__builtin_ia32_vfmaddpd512_maskz: + case X86::BI__builtin_ia32_vfmaddps512_mask: + case X86::BI__builtin_ia32_vfmaddps512_mask3: + case X86::BI__builtin_ia32_vfmaddps512_maskz: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: + case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: + case X86::BI__builtin_ia32_vfmaddsubps512_mask: + case X86::BI__builtin_ia32_vfmaddsubps512_mask3: + case X86::BI__builtin_ia32_vfmaddsubps512_maskz: + case X86::BI__builtin_ia32_vfmsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubps512_mask3: + case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: + case X86::BI__builtin_ia32_vfmsubaddps512_mask3: + case X86::BI__builtin_ia32_vfnmaddpd512_mask: + case X86::BI__builtin_ia32_vfnmaddps512_mask: + case X86::BI__builtin_ia32_vfnmsubpd512_mask: + case X86::BI__builtin_ia32_vfnmsubpd512_mask3: + case X86::BI__builtin_ia32_vfnmsubps512_mask: + case X86::BI__builtin_ia32_vfnmsubps512_mask3: + case X86::BI__builtin_ia32_vfmaddsd3_mask: + case X86::BI__builtin_ia32_vfmaddsd3_maskz: + case X86::BI__builtin_ia32_vfmaddsd3_mask3: + case X86::BI__builtin_ia32_vfmaddss3_mask: + case X86::BI__builtin_ia32_vfmaddss3_maskz: + case X86::BI__builtin_ia32_vfmaddss3_mask3: + ArgNum = 4; + HasRC = true; + break; + case X86::BI__builtin_ia32_getmantsd_round_mask: + case X86::BI__builtin_ia32_getmantss_round_mask: + ArgNum = 5; + HasRC = true; + break; + } + + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit + // is set. If the intrinsic has rounding control(bits 1:0), make sure its only + // combined with ROUND_NO_EXC. + if (Result == 4/*ROUND_CUR_DIRECTION*/ || + Result == 8/*ROUND_NO_EXC*/ || + (HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11)) + return false; + + return Diag(TheCall->getLocStart(), diag::err_x86_builtin_invalid_rounding) + << Arg->getSourceRange(); +} + +bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); - case X86::BI__builtin_ms_va_start: + + if (BuiltinID == X86::BI__builtin_ms_va_start) return SemaBuiltinMSVAStart(TheCall); - case X86::BI__builtin_ia32_extractf64x4_mask: - case X86::BI__builtin_ia32_extracti64x4_mask: - case X86::BI__builtin_ia32_extractf32x8_mask: - case X86::BI__builtin_ia32_extracti32x8_mask: - case X86::BI__builtin_ia32_extractf64x2_256_mask: - case X86::BI__builtin_ia32_extracti64x2_256_mask: - case X86::BI__builtin_ia32_extractf32x4_256_mask: - case X86::BI__builtin_ia32_extracti32x4_256_mask: - i = 1; l = 0; u = 1; - break; + + // If the intrinsic has rounding or SAE make sure its valid. + if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) + return true; + + // For intrinsics which take an immediate value as part of the instruction, + // range check them here. + int i = 0, l = 0, u = 0; + switch (BuiltinID) { + default: + return false; case X86::BI_mm_prefetch: - case X86::BI__builtin_ia32_extractf32x4_mask: - case X86::BI__builtin_ia32_extracti32x4_mask: - case X86::BI__builtin_ia32_extractf64x2_512_mask: - case X86::BI__builtin_ia32_extracti64x2_512_mask: i = 1; l = 0; u = 3; break; - case X86::BI__builtin_ia32_insertf32x8_mask: - case X86::BI__builtin_ia32_inserti32x8_mask: - case X86::BI__builtin_ia32_insertf64x4_mask: - case X86::BI__builtin_ia32_inserti64x4_mask: - case X86::BI__builtin_ia32_insertf64x2_256_mask: - case X86::BI__builtin_ia32_inserti64x2_256_mask: - case X86::BI__builtin_ia32_insertf32x4_256_mask: - case X86::BI__builtin_ia32_inserti32x4_256_mask: - i = 2; l = 0; u = 1; - break; case X86::BI__builtin_ia32_sha1rnds4: case X86::BI__builtin_ia32_shuf_f32x4_256_mask: case X86::BI__builtin_ia32_shuf_f64x2_256_mask: case X86::BI__builtin_ia32_shuf_i32x4_256_mask: case X86::BI__builtin_ia32_shuf_i64x2_256_mask: - case X86::BI__builtin_ia32_insertf64x2_512_mask: - case X86::BI__builtin_ia32_inserti64x2_512_mask: - case X86::BI__builtin_ia32_insertf32x4_mask: - case X86::BI__builtin_ia32_inserti32x4_mask: i = 2; l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: @@ -1909,33 +2121,6 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_prord256_mask: case X86::BI__builtin_ia32_prorq128_mask: case X86::BI__builtin_ia32_prorq256_mask: - case X86::BI__builtin_ia32_psllwi512_mask: - case X86::BI__builtin_ia32_psllwi128_mask: - case X86::BI__builtin_ia32_psllwi256_mask: - case X86::BI__builtin_ia32_psrldi128_mask: - case X86::BI__builtin_ia32_psrldi256_mask: - case X86::BI__builtin_ia32_psrldi512_mask: - case X86::BI__builtin_ia32_psrlqi128_mask: - case X86::BI__builtin_ia32_psrlqi256_mask: - case X86::BI__builtin_ia32_psrlqi512_mask: - case X86::BI__builtin_ia32_psrawi512_mask: - case X86::BI__builtin_ia32_psrawi128_mask: - case X86::BI__builtin_ia32_psrawi256_mask: - case X86::BI__builtin_ia32_psrlwi512_mask: - case X86::BI__builtin_ia32_psrlwi128_mask: - case X86::BI__builtin_ia32_psrlwi256_mask: - case X86::BI__builtin_ia32_psradi128_mask: - case X86::BI__builtin_ia32_psradi256_mask: - case X86::BI__builtin_ia32_psradi512_mask: - case X86::BI__builtin_ia32_psraqi128_mask: - case X86::BI__builtin_ia32_psraqi256_mask: - case X86::BI__builtin_ia32_psraqi512_mask: - case X86::BI__builtin_ia32_pslldi128_mask: - case X86::BI__builtin_ia32_pslldi256_mask: - case X86::BI__builtin_ia32_pslldi512_mask: - case X86::BI__builtin_ia32_psllqi128_mask: - case X86::BI__builtin_ia32_psllqi256_mask: - case X86::BI__builtin_ia32_psllqi512_mask: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclassps128_mask: @@ -1969,15 +2154,7 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr256: - case X86::BI__builtin_ia32_palignr128_mask: - case X86::BI__builtin_ia32_palignr256_mask: case X86::BI__builtin_ia32_palignr512_mask: - case X86::BI__builtin_ia32_alignq512_mask: - case X86::BI__builtin_ia32_alignd512_mask: - case X86::BI__builtin_ia32_alignd128_mask: - case X86::BI__builtin_ia32_alignd256_mask: - case X86::BI__builtin_ia32_alignq128_mask: - case X86::BI__builtin_ia32_alignq256_mask: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: case X86::BI__builtin_ia32_shuf_f32x4_mask: @@ -2271,7 +2448,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // Refuse POD arguments that weren't caught by the format string // checks above. - if (CallType != VariadicDoesNotApply) { + auto *FD = dyn_cast_or_null<FunctionDecl>(FDecl); + if (CallType != VariadicDoesNotApply && + (!FD || FD->getBuiltinID() != Builtin::BI__noop)) { unsigned NumParams = Proto ? Proto->getNumParams() : FDecl && isa<FunctionDecl>(FDecl) ? cast<FunctionDecl>(FDecl)->getNumParams() @@ -2340,7 +2519,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, if (!FnInfo) return false; - CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo); + CheckAbsoluteValueFunction(TheCall, FDecl); + CheckMaxUnsignedZero(TheCall, FDecl); + if (getLangOpts().ObjC1) DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); @@ -2691,6 +2872,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Ty = Context.getPointerDiffType(); else { Expr *ValArg = TheCall->getArg(i); + // 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; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = @@ -3267,21 +3451,46 @@ bool Sema::CheckObjCString(Expr *Arg) { if (Literal->containsNonAsciiOrNull()) { StringRef String = Literal->getString(); unsigned NumBytes = String.size(); - SmallVector<UTF16, 128> ToBuf(NumBytes); - const UTF8 *FromPtr = (const UTF8 *)String.data(); - UTF16 *ToPtr = &ToBuf[0]; - - ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, - &ToPtr, ToPtr + NumBytes, - strictConversion); + SmallVector<llvm::UTF16, 128> ToBuf(NumBytes); + const llvm::UTF8 *FromPtr = (const llvm::UTF8 *)String.data(); + llvm::UTF16 *ToPtr = &ToBuf[0]; + + llvm::ConversionResult Result = + llvm::ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, &ToPtr, + ToPtr + NumBytes, llvm::strictConversion); // Check for conversion failure. - if (Result != conversionOK) + if (Result != llvm::conversionOK) Diag(Arg->getLocStart(), diag::warn_cfstring_truncated) << Arg->getSourceRange(); } return false; } +/// CheckObjCString - Checks that the format string argument to the os_log() +/// and os_trace() functions is correct, and converts it to const char *. +ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { + Arg = Arg->IgnoreParenCasts(); + auto *Literal = dyn_cast<StringLiteral>(Arg); + if (!Literal) { + if (auto *ObjcLiteral = dyn_cast<ObjCStringLiteral>(Arg)) { + Literal = ObjcLiteral->getString(); + } + } + + if (!Literal || (!Literal->isAscii() && !Literal->isUTF8())) { + return ExprError( + Diag(Arg->getLocStart(), diag::err_os_log_format_not_string_constant) + << Arg->getSourceRange()); + } + + ExprResult Result(Literal); + QualType ResultTy = Context.getPointerType(Context.CharTy.withConst()); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, ResultTy, false); + Result = PerformCopyInitialization(Entity, SourceLocation(), Result); + return Result; +} + /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. @@ -3357,8 +3566,17 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { Diag(TheCall->getArg(1)->getLocStart(), diag::warn_second_arg_of_va_start_not_last_named_param); else if (IsCRegister || Type->isReferenceType() || - Type->isPromotableIntegerType() || - Type->isSpecificBuiltinType(BuiltinType::Float)) { + Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { + // Promotable integers are UB, but enumerations need a bit of + // extra checking to see what their promotable type actually is. + if (!Type->isPromotableIntegerType()) + return false; + if (!Type->isEnumeralType()) + return true; + const EnumDecl *ED = Type->getAs<EnumType>()->getDecl(); + return !(ED && + Context.typesAreCompatible(ED->getPromotionType(), Type)); + }()) { unsigned Reason = 0; if (Type->isReferenceType()) Reason = 1; else if (IsCRegister) Reason = 2; @@ -3532,14 +3750,18 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> double, remove it. + // If this is an implicit conversion from float -> float or double, remove it. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { - Expr *CastArg = Cast->getSubExpr(); - if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) && - "promotion from float to double is the only expected cast here"); - Cast->setSubExpr(nullptr); - TheCall->setArg(NumArgs-1, CastArg); + // Only remove standard FloatCasts, leaving other casts inplace + if (Cast->getCastKind() == CK_FloatingCast) { + Expr *CastArg = Cast->getSubExpr(); + if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { + assert((Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::Float)) && + "promotion from float to either float or double is the only expected cast here"); + Cast->setSubExpr(nullptr); + TheCall->setArg(NumArgs-1, CastArg); + } } } @@ -3696,6 +3918,42 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { return false; } +/// Handle __builtin_alloca_with_align. This is declared +/// as (size_t, size_t) where the second size_t must be a power of 2 greater +/// than 8. +bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { + // The alignment must be a constant integer. + Expr *Arg = TheCall->getArg(1); + + // We can't check the value of a dependent argument. + if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { + if (const auto *UE = + dyn_cast<UnaryExprOrTypeTraitExpr>(Arg->IgnoreParenImpCasts())) + if (UE->getKind() == UETT_AlignOf) + Diag(TheCall->getLocStart(), diag::warn_alloca_align_alignof) + << Arg->getSourceRange(); + + llvm::APSInt Result = Arg->EvaluateKnownConstInt(Context); + + if (!Result.isPowerOf2()) + return Diag(TheCall->getLocStart(), + diag::err_alignment_not_power_of_two) + << Arg->getSourceRange(); + + if (Result < Context.getCharWidth()) + return Diag(TheCall->getLocStart(), diag::err_alignment_too_small) + << (unsigned)Context.getCharWidth() + << Arg->getSourceRange(); + + if (Result > INT32_MAX) + return Diag(TheCall->getLocStart(), diag::err_alignment_too_big) + << INT32_MAX + << Arg->getSourceRange(); + } + + return false; +} + /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { @@ -3734,6 +3992,86 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { return false; } +bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { + unsigned BuiltinID = + cast<FunctionDecl>(TheCall->getCalleeDecl())->getBuiltinID(); + bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; + + unsigned NumArgs = TheCall->getNumArgs(); + unsigned NumRequiredArgs = IsSizeCall ? 1 : 2; + if (NumArgs < NumRequiredArgs) { + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /* function call */ << NumRequiredArgs << NumArgs + << TheCall->getSourceRange(); + } + if (NumArgs >= NumRequiredArgs + 0x100) { + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs + << TheCall->getSourceRange(); + } + unsigned i = 0; + + // For formatting call, check buffer arg. + if (!IsSizeCall) { + ExprResult Arg(TheCall->getArg(i)); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, Context.VoidPtrTy, false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(i, Arg.get()); + i++; + } + + // Check string literal arg. + unsigned FormatIdx = i; + { + ExprResult Arg = CheckOSLogFormatStringArg(TheCall->getArg(i)); + if (Arg.isInvalid()) + return true; + TheCall->setArg(i, Arg.get()); + i++; + } + + // Make sure variadic args are scalar. + unsigned FirstDataArg = i; + while (i < NumArgs) { + ExprResult Arg = DefaultVariadicArgumentPromotion( + TheCall->getArg(i), VariadicFunction, nullptr); + if (Arg.isInvalid()) + return true; + CharUnits ArgSize = Context.getTypeSizeInChars(Arg.get()->getType()); + if (ArgSize.getQuantity() >= 0x100) { + return Diag(Arg.get()->getLocEnd(), diag::err_os_log_argument_too_big) + << i << (int)ArgSize.getQuantity() << 0xff + << TheCall->getSourceRange(); + } + TheCall->setArg(i, Arg.get()); + i++; + } + + // Check formatting specifiers. NOTE: We're only doing this for the non-size + // call to avoid duplicate diagnostics. + if (!IsSizeCall) { + llvm::SmallBitVector CheckedVarArgs(NumArgs, false); + ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs()); + bool Success = CheckFormatArguments( + Args, /*HasVAListArg*/ false, FormatIdx, FirstDataArg, FST_OSLog, + VariadicFunction, TheCall->getLocStart(), SourceRange(), + CheckedVarArgs); + if (!Success) + return true; + } + + if (IsSizeCall) { + TheCall->setType(Context.getSizeType()); + } else { + TheCall->setType(Context.VoidPtrTy); + } + return false; +} + /// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, @@ -3861,7 +4199,7 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, SmallVector<int, 5> Ranges; if (FiveFields) - Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 7, 15, 15}); + Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7}); else Ranges.append({15, 7, 15}); @@ -3980,7 +4318,95 @@ enum StringLiteralCheckType { }; } // end anonymous namespace -static void CheckFormatString(Sema &S, const StringLiteral *FExpr, +static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, + BinaryOperatorKind BinOpKind, + bool AddendIsRight) { + unsigned BitWidth = Offset.getBitWidth(); + unsigned AddendBitWidth = Addend.getBitWidth(); + // There might be negative interim results. + if (Addend.isUnsigned()) { + Addend = Addend.zext(++AddendBitWidth); + Addend.setIsSigned(true); + } + // Adjust the bit width of the APSInts. + if (AddendBitWidth > BitWidth) { + Offset = Offset.sext(AddendBitWidth); + BitWidth = AddendBitWidth; + } else if (BitWidth > AddendBitWidth) { + Addend = Addend.sext(BitWidth); + } + + bool Ov = false; + llvm::APSInt ResOffset = Offset; + if (BinOpKind == BO_Add) + ResOffset = Offset.sadd_ov(Addend, Ov); + else { + assert(AddendIsRight && BinOpKind == BO_Sub && + "operator must be add or sub with addend on the right"); + ResOffset = Offset.ssub_ov(Addend, Ov); + } + + // We add an offset to a pointer here so we should support an offset as big as + // possible. + if (Ov) { + assert(BitWidth <= UINT_MAX / 2 && "index (intermediate) result too big"); + Offset = Offset.sext(2 * BitWidth); + sumOffsets(Offset, Addend, BinOpKind, AddendIsRight); + return; + } + + Offset = ResOffset; +} + +namespace { +// This is a wrapper class around StringLiteral to support offsetted string +// literals as format strings. It takes the offset into account when returning +// the string and its length or the source locations to display notes correctly. +class FormatStringLiteral { + const StringLiteral *FExpr; + int64_t Offset; + + public: + FormatStringLiteral(const StringLiteral *fexpr, int64_t Offset = 0) + : FExpr(fexpr), Offset(Offset) {} + + StringRef getString() const { + return FExpr->getString().drop_front(Offset); + } + + unsigned getByteLength() const { + return FExpr->getByteLength() - getCharByteWidth() * Offset; + } + unsigned getLength() const { return FExpr->getLength() - Offset; } + unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); } + + StringLiteral::StringKind getKind() const { return FExpr->getKind(); } + + QualType getType() const { return FExpr->getType(); } + + bool isAscii() const { return FExpr->isAscii(); } + bool isWide() const { return FExpr->isWide(); } + bool isUTF8() const { return FExpr->isUTF8(); } + bool isUTF16() const { return FExpr->isUTF16(); } + bool isUTF32() const { return FExpr->isUTF32(); } + bool isPascal() const { return FExpr->isPascal(); } + + SourceLocation getLocationOfByte( + unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, + const TargetInfo &Target, unsigned *StartToken = nullptr, + unsigned *StartTokenByteOffset = nullptr) const { + return FExpr->getLocationOfByte(ByteNo + Offset, SM, Features, Target, + StartToken, StartTokenByteOffset); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return FExpr->getLocStart().getLocWithOffset(Offset); + } + SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); } +}; +} // end anonymous namespace + +static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, ArrayRef<const Expr *> Args, bool HasVAListArg, unsigned format_idx, @@ -4001,8 +4427,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, unsigned firstDataArg, Sema::FormatStringType Type, Sema::VariadicCallType CallType, bool InFunctionCall, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg) { + UncoveredArgHandler &UncoveredArg, + llvm::APSInt Offset) { tryAgain: + assert(Offset.isSigned() && "invalid offset"); + if (E->isTypeDependent() || E->isValueDependent()) return SLCT_NotALiteral; @@ -4036,6 +4465,10 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, CheckLeft = false; } + // We need to maintain the offsets for the right and the left hand side + // separately to check if every possible indexed expression is a valid + // string literal. They might have different offsets for different string + // literals in the end. StringLiteralCheckType Left; if (!CheckLeft) Left = SLCT_UncheckedLiteral; @@ -4043,16 +4476,17 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg); - if (Left == SLCT_NotALiteral || !CheckRight) + CheckedVarArgs, UncoveredArg, Offset); + if (Left == SLCT_NotALiteral || !CheckRight) { return Left; + } } StringLiteralCheckType Right = checkFormatStringExpr(S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg); + UncoveredArg, Offset); return (CheckLeft && Left < Right) ? Left : Right; } @@ -4105,8 +4539,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Init, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*InFunctionCall*/false, CheckedVarArgs, - UncoveredArg); + /*InFunctionCall*/ false, CheckedVarArgs, + UncoveredArg, Offset); } } @@ -4161,7 +4595,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg); + CheckedVarArgs, UncoveredArg, Offset); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || @@ -4171,13 +4605,27 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg); + UncoveredArg, Offset); } } } return SLCT_NotALiteral; } + case Stmt::ObjCMessageExprClass: { + const auto *ME = cast<ObjCMessageExpr>(E); + if (const auto *ND = ME->getMethodDecl()) { + if (const auto *FA = ND->getAttr<FormatArgAttr>()) { + unsigned ArgIndex = FA->getFormatIdx(); + const Expr *Arg = ME->getArg(ArgIndex - 1); + return checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + } + } + + return SLCT_NotALiteral; + } case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: { const StringLiteral *StrE = nullptr; @@ -4188,7 +4636,13 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, StrE = cast<StringLiteral>(E); if (StrE) { - CheckFormatString(S, StrE, E, Args, HasVAListArg, format_idx, + if (Offset.isNegative() || Offset > StrE->getLength()) { + // TODO: It would be better to have an explicit warning for out of + // bounds literals. + return SLCT_NotALiteral; + } + FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue()); + CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx, firstDataArg, Type, InFunctionCall, CallType, CheckedVarArgs, UncoveredArg); return SLCT_CheckedLiteral; @@ -4196,6 +4650,50 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return SLCT_NotALiteral; } + case Stmt::BinaryOperatorClass: { + llvm::APSInt LResult; + llvm::APSInt RResult; + + const BinaryOperator *BinOp = cast<BinaryOperator>(E); + + // A string literal + an int offset is still a string literal. + if (BinOp->isAdditiveOp()) { + bool LIsInt = BinOp->getLHS()->EvaluateAsInt(LResult, S.Context); + bool RIsInt = BinOp->getRHS()->EvaluateAsInt(RResult, S.Context); + + if (LIsInt != RIsInt) { + BinaryOperatorKind BinOpKind = BinOp->getOpcode(); + + if (LIsInt) { + if (BinOpKind == BO_Add) { + sumOffsets(Offset, LResult, BinOpKind, RIsInt); + E = BinOp->getRHS(); + goto tryAgain; + } + } else { + sumOffsets(Offset, RResult, BinOpKind, RIsInt); + E = BinOp->getLHS(); + goto tryAgain; + } + } + } + + return SLCT_NotALiteral; + } + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UnaOp = cast<UnaryOperator>(E); + auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr()); + if (UnaOp->getOpcode() == clang::UO_AddrOf && ASE) { + llvm::APSInt IndexResult; + if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) { + sumOffsets(Offset, IndexResult, BO_Add, /*RHS is int*/ true); + E = ASE->getBase(); + goto tryAgain; + } + } + + return SLCT_NotALiteral; + } default: return SLCT_NotALiteral; @@ -4204,15 +4702,16 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { return llvm::StringSwitch<FormatStringType>(Format->getType()->getName()) - .Case("scanf", FST_Scanf) - .Cases("printf", "printf0", FST_Printf) - .Cases("NSString", "CFString", FST_NSString) - .Case("strftime", FST_Strftime) - .Case("strfmon", FST_Strfmon) - .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) - .Case("freebsd_kprintf", FST_FreeBSDKPrintf) - .Case("os_trace", FST_OSTrace) - .Default(FST_Unknown); + .Case("scanf", FST_Scanf) + .Cases("printf", "printf0", FST_Printf) + .Cases("NSString", "CFString", FST_NSString) + .Case("strftime", FST_Strftime) + .Case("strfmon", FST_Strfmon) + .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) + .Case("freebsd_kprintf", FST_FreeBSDKPrintf) + .Case("os_trace", FST_OSLog) + .Case("os_log", FST_OSLog) + .Default(FST_Unknown); } /// CheckFormatArguments - Check calls to printf and scanf (and similar @@ -4262,8 +4761,9 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, StringLiteralCheckType CT = checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*IsFunctionCall*/true, CheckedVarArgs, - UncoveredArg); + /*IsFunctionCall*/ true, CheckedVarArgs, + UncoveredArg, + /*no string offset*/ llvm::APSInt(64, false) = 0); // Generate a diagnostic where an uncovered argument is detected. if (UncoveredArg.hasUncoveredArg()) { @@ -4319,8 +4819,9 @@ namespace { class CheckFormatHandler : public analyze_format_string::FormatStringHandler { protected: Sema &S; - const StringLiteral *FExpr; + const FormatStringLiteral *FExpr; const Expr *OrigFormatExpr; + const Sema::FormatStringType FSType; const unsigned FirstDataArg; const unsigned NumDataArgs; const char *Beg; // Start of format string. @@ -4336,21 +4837,20 @@ protected: UncoveredArgHandler &UncoveredArg; public: - CheckFormatHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, unsigned firstDataArg, + CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr, + const Expr *origFormatExpr, + const Sema::FormatStringType type, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, - unsigned formatIdx, bool inFunctionCall, - Sema::VariadicCallType callType, + ArrayRef<const Expr *> Args, unsigned formatIdx, + bool inFunctionCall, Sema::VariadicCallType callType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), - FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), - Beg(beg), HasVAListArg(hasVAListArg), - Args(Args), FormatIdx(formatIdx), - usesPositionalArgs(false), atFirstArg(true), - inFunctionCall(inFunctionCall), CallType(callType), - CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { + : 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); CoveredArgs.reset(); } @@ -4436,7 +4936,8 @@ getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { } SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) { - return S.getLocationOfStringLiteralByte(FExpr, x - Beg); + return FExpr->getLocationOfByte(x - Beg, S.getSourceManager(), + S.getLangOpts(), S.Context.getTargetInfo()); } void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier, @@ -4647,16 +5148,16 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, // hex value. std::string CodePointStr; if (!llvm::sys::locale::isPrint(*csStart)) { - UTF32 CodePoint; - const UTF8 **B = reinterpret_cast<const UTF8 **>(&csStart); - const UTF8 *E = - reinterpret_cast<const UTF8 *>(csStart + csLen); - ConversionResult Result = - llvm::convertUTF8Sequence(B, E, &CodePoint, strictConversion); - - if (Result != conversionOK) { + llvm::UTF32 CodePoint; + const llvm::UTF8 **B = reinterpret_cast<const llvm::UTF8 **>(&csStart); + const llvm::UTF8 *E = + reinterpret_cast<const llvm::UTF8 *>(csStart + csLen); + llvm::ConversionResult Result = + llvm::convertUTF8Sequence(B, E, &CodePoint, llvm::strictConversion); + + if (Result != llvm::conversionOK) { unsigned char FirstChar = *csStart; - CodePoint = (UTF32)FirstChar; + CodePoint = (llvm::UTF32)FirstChar; } llvm::raw_string_ostream OS(CodePointStr); @@ -4772,24 +5273,28 @@ void CheckFormatHandler::EmitFormatDiagnostic( namespace { class CheckPrintfHandler : public CheckFormatHandler { - bool ObjCContext; - public: - CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, unsigned firstDataArg, - unsigned numDataArgs, bool isObjC, - const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, + CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr, + const Expr *origFormatExpr, + const Sema::FormatStringType type, unsigned firstDataArg, + unsigned numDataArgs, bool isObjC, const char *beg, + bool hasVAListArg, ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, - numDataArgs, beg, hasVAListArg, Args, - formatIdx, inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg), - ObjCContext(isObjC) - {} + : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, + numDataArgs, beg, hasVAListArg, Args, formatIdx, + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg) {} + + bool isObjCContext() const { return FSType == Sema::FST_NSString; } + + /// Returns true if '%@' specifiers are allowed in the format string. + bool allowsObjCArg() const { + return FSType == Sema::FST_NSString || FSType == Sema::FST_OSLog || + FSType == Sema::FST_OSTrace; + } bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -5143,11 +5648,54 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier // Check for using an Objective-C specific conversion specifier // in a non-ObjC literal. - if (!ObjCContext && CS.isObjCArg()) { + if (!allowsObjCArg() && CS.isObjCArg()) { + return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, + specifierLen); + } + + // %P can only be used with os_log. + if (FSType != Sema::FST_OSLog && CS.getKind() == ConversionSpecifier::PArg) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, specifierLen); } + // %n is not allowed with os_log. + if (FSType == Sema::FST_OSLog && CS.getKind() == ConversionSpecifier::nArg) { + EmitFormatDiagnostic(S.PDiag(diag::warn_os_log_format_narg), + getLocationOfByte(CS.getStart()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + + return true; + } + + // Only scalars are allowed for os_trace. + if (FSType == Sema::FST_OSTrace && + (CS.getKind() == ConversionSpecifier::PArg || + CS.getKind() == ConversionSpecifier::sArg || + CS.getKind() == ConversionSpecifier::ObjCObjArg)) { + return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, + specifierLen); + } + + // Check for use of public/private annotation outside of os_log(). + if (FSType != Sema::FST_OSLog) { + if (FS.isPublic().isSet()) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) + << "public", + getLocationOfByte(FS.isPublic().getPosition()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + if (FS.isPrivate().isSet()) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) + << "private", + getLocationOfByte(FS.isPrivate().getPosition()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + } + // Check for invalid use of field width if (!FS.hasValidFieldWidth()) { HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0, @@ -5160,6 +5708,15 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier startSpecifier, specifierLen); } + // Precision is mandatory for %P specifier. + if (CS.getKind() == ConversionSpecifier::PArg && + FS.getPrecision().getHowSpecified() == OptionalAmount::NotSpecified) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_no_precision), + getLocationOfByte(startSpecifier), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + // Check each flag does not conflict with any other component. if (!FS.hasValidThousandsGroupingPrefix()) HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen); @@ -5309,8 +5866,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, using namespace analyze_printf; // Now type check the data expression that matches the // format specifier. - const analyze_printf::ArgType &AT = FS.getArgType(S.Context, - ObjCContext); + const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext()); if (!AT.isValid()) return true; @@ -5365,7 +5921,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // If the argument is an integer of some kind, believe the %C and suggest // a cast instead of changing the conversion specifier. QualType IntendedTy = ExprTy; - if (ObjCContext && + if (isObjCContext() && FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) { if (ExprTy->isIntegralOrUnscopedEnumerationType() && !ExprTy->isCharType()) { @@ -5406,8 +5962,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(), - S.Context, ObjCContext); + bool success = + fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); if (success) { // Get the fix string from the fixed format specifier @@ -5562,20 +6118,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, namespace { class CheckScanfHandler : public CheckFormatHandler { public: - CheckScanfHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, unsigned firstDataArg, - unsigned numDataArgs, const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, - unsigned formatIdx, bool inFunctionCall, - Sema::VariadicCallType CallType, + CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, + const Expr *origFormatExpr, Sema::FormatStringType type, + unsigned firstDataArg, unsigned numDataArgs, + const char *beg, bool hasVAListArg, + ArrayRef<const Expr *> Args, unsigned formatIdx, + bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, - numDataArgs, beg, hasVAListArg, - Args, formatIdx, inFunctionCall, CallType, - CheckedVarArgs, UncoveredArg) - {} - + : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, + numDataArgs, beg, hasVAListArg, Args, formatIdx, + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg) {} + bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; @@ -5733,7 +6288,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } -static void CheckFormatString(Sema &S, const StringLiteral *FExpr, +static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, ArrayRef<const Expr *> Args, bool HasVAListArg, unsigned format_idx, @@ -5785,13 +6340,13 @@ static void CheckFormatString(Sema &S, const StringLiteral *FExpr, } if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || - Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSTrace) { - CheckPrintfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, - numDataArgs, (Type == Sema::FST_NSString || - Type == Sema::FST_OSTrace), - Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg); + Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSLog || + Type == Sema::FST_OSTrace) { + CheckPrintfHandler H( + S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs, + (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, + HasVAListArg, Args, format_idx, inFunctionCall, CallType, + CheckedVarArgs, UncoveredArg); if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, S.getLangOpts(), @@ -5799,10 +6354,9 @@ static void CheckFormatString(Sema &S, const StringLiteral *FExpr, Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); } else if (Type == Sema::FST_Scanf) { - CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, - Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg); + CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, + numDataArgs, Str, HasVAListArg, Args, format_idx, + inFunctionCall, CallType, CheckedVarArgs, UncoveredArg); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, S.getLangOpts(), @@ -6118,23 +6672,14 @@ static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range, << FunctionName; } -static bool IsFunctionStdAbs(const FunctionDecl *FDecl) { +template <std::size_t StrLen> +static bool IsStdFunction(const FunctionDecl *FDecl, + const char (&Str)[StrLen]) { if (!FDecl) return false; - - if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr("abs")) - return false; - - const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(FDecl->getDeclContext()); - - while (ND && ND->isInlineNamespace()) { - ND = dyn_cast<NamespaceDecl>(ND->getDeclContext()); - } - - if (!ND || !ND->getIdentifier() || !ND->getIdentifier()->isStr("std")) + if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr(Str)) return false; - - if (!isa<TranslationUnitDecl>(ND->getDeclContext())) + if (!FDecl->isInStdNamespace()) return false; return true; @@ -6142,13 +6687,12 @@ static bool IsFunctionStdAbs(const FunctionDecl *FDecl) { // Warn when using the wrong abs() function. void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, - const FunctionDecl *FDecl, - IdentifierInfo *FnInfo) { + const FunctionDecl *FDecl) { if (Call->getNumArgs() != 1) return; unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl); - bool IsStdAbs = IsFunctionStdAbs(FDecl); + bool IsStdAbs = IsStdFunction(FDecl, "abs"); if (AbsKind == 0 && !IsStdAbs) return; @@ -6221,6 +6765,69 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); } +//===--- CHECK: Warn on use of std::max and unsigned zero. r---------------===// +void Sema::CheckMaxUnsignedZero(const CallExpr *Call, + const FunctionDecl *FDecl) { + if (!Call || !FDecl) return; + + // Ignore template specializations and macros. + if (!ActiveTemplateInstantiations.empty()) return; + if (Call->getExprLoc().isMacroID()) return; + + // Only care about the one template argument, two function parameter std::max + if (Call->getNumArgs() != 2) return; + if (!IsStdFunction(FDecl, "max")) return; + const auto * ArgList = FDecl->getTemplateSpecializationArgs(); + if (!ArgList) return; + if (ArgList->size() != 1) return; + + // Check that template type argument is unsigned integer. + const auto& TA = ArgList->get(0); + if (TA.getKind() != TemplateArgument::Type) return; + QualType ArgType = TA.getAsType(); + if (!ArgType->isUnsignedIntegerType()) return; + + // See if either argument is a literal zero. + auto IsLiteralZeroArg = [](const Expr* E) -> bool { + const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E); + if (!MTE) return false; + const auto *Num = dyn_cast<IntegerLiteral>(MTE->GetTemporaryExpr()); + if (!Num) return false; + if (Num->getValue() != 0) return false; + return true; + }; + + const Expr *FirstArg = Call->getArg(0); + const Expr *SecondArg = Call->getArg(1); + const bool IsFirstArgZero = IsLiteralZeroArg(FirstArg); + const bool IsSecondArgZero = IsLiteralZeroArg(SecondArg); + + // Only warn when exactly one argument is zero. + if (IsFirstArgZero == IsSecondArgZero) return; + + SourceRange FirstRange = FirstArg->getSourceRange(); + SourceRange SecondRange = SecondArg->getSourceRange(); + + SourceRange ZeroRange = IsFirstArgZero ? FirstRange : SecondRange; + + Diag(Call->getExprLoc(), diag::warn_max_unsigned_zero) + << IsFirstArgZero << Call->getCallee()->getSourceRange() << ZeroRange; + + // Deduce what parts to remove so that "std::max(0u, foo)" becomes "(foo)". + SourceRange RemovalRange; + if (IsFirstArgZero) { + RemovalRange = SourceRange(FirstRange.getBegin(), + SecondRange.getBegin().getLocWithOffset(-1)); + } else { + RemovalRange = SourceRange(getLocForEndOfToken(FirstRange.getEnd()), + SecondRange.getEnd()); + } + + Diag(Call->getExprLoc(), diag::note_remove_max_call) + << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()) + << FixItHint::CreateRemoval(RemovalRange); +} + //===--- CHECK: Standard memory functions ---------------------------------===// /// \brief Takes the expression passed to the size_t parameter of functions @@ -6320,13 +6927,15 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. - unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3); + unsigned ExpectedNumArgs = + (BId == Builtin::BIstrndup || BId == Builtin::BIbzero ? 2 : 3); if (Call->getNumArgs() < ExpectedNumArgs) return; - unsigned LastArg = (BId == Builtin::BImemset || + unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); - unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2); + unsigned LenArg = + (BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); if (CheckMemorySizeofForComparison(*this, LenExpr, FnName, @@ -6338,6 +6947,13 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); llvm::FoldingSetNodeID SizeOfArgID; + // Although widely used, 'bzero' is not a standard function. Be more strict + // with the argument types before allowing diagnostics and only allow the + // form bzero(ptr, sizeof(...)). + QualType FirstArgTy = Call->getArg(0)->IgnoreParenImpCasts()->getType(); + if (BId == Builtin::BIbzero && !FirstArgTy->getAs<PointerType>()) + return; + for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); @@ -7960,6 +8576,24 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, return false; // White-list bool bitfields. + QualType BitfieldType = Bitfield->getType(); + if (BitfieldType->isBooleanType()) + return false; + + if (BitfieldType->isEnumeralType()) { + EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl(); + // If the underlying enum type was not explicitly specified as an unsigned + // type and the enum contain only positive values, MSVC++ will cause an + // inconsistency by storing this as a signed type. + if (S.getLangOpts().CPlusPlus11 && + !BitfieldEnumDecl->getIntegerTypeSourceInfo() && + BitfieldEnumDecl->getNumPositiveBits() > 0 && + BitfieldEnumDecl->getNumNegativeBits() == 0) { + S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield) + << BitfieldEnumDecl->getNameAsString(); + } + } + if (Bitfield->getType()->isBooleanType()) return false; @@ -7979,18 +8613,17 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, unsigned OriginalWidth = Value.getBitWidth(); unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); - if (Value.isSigned() && Value.isNegative()) + if (!Value.isSigned() || Value.isNegative()) if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit)) - if (UO->getOpcode() == UO_Minus) - if (isa<IntegerLiteral>(UO->getSubExpr())) - OriginalWidth = Value.getMinSignedBits(); + if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not) + OriginalWidth = Value.getMinSignedBits(); if (OriginalWidth <= FieldWidth) return false; // Compute the value which the bitfield will contain. llvm::APSInt TruncatedValue = Value.trunc(FieldWidth); - TruncatedValue.setIsSigned(Bitfield->getType()->isSignedIntegerType()); + TruncatedValue.setIsSigned(BitfieldType->isSignedIntegerType()); // Check whether the stored value is equal to the original value. TruncatedValue = TruncatedValue.extend(OriginalWidth); @@ -8515,6 +9148,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, DiagnoseNullConversion(S, E, T, CC); + S.DiscardMisalignedMemberAddress(Target, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -8776,25 +9411,19 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { } // end anonymous namespace -static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, - unsigned Start, unsigned End) { - bool IllegalParams = false; - for (unsigned I = Start; I <= End; ++I) { - QualType Ty = TheCall->getArg(I)->getType(); - // Taking into account implicit conversions, - // allow any integer within 32 bits range - if (!Ty->isIntegerType() || - S.Context.getTypeSizeInChars(Ty).getQuantity() > 4) { - S.Diag(TheCall->getArg(I)->getLocStart(), - diag::err_opencl_enqueue_kernel_invalid_local_size_type); - IllegalParams = true; - } - // Potentially emit standard warnings for implicit conversions if enabled - // using -Wconversion. - CheckImplicitConversion(S, TheCall->getArg(I), S.Context.UnsignedIntTy, - TheCall->getArg(I)->getLocStart()); +/// 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, + // allow any integer. + if (!E->getType()->isIntegerType()) { + S.Diag(E->getLocStart(), + diag::err_opencl_enqueue_kernel_invalid_local_size_type); + return true; } - return IllegalParams; + // Potentially emit standard warnings for implicit conversions if enabled + // using -Wconversion. + CheckImplicitConversion(S, E, IntT, E->getLocStart()); + return false; } // Helper function for Sema::DiagnoseAlwaysNonNullPointer. @@ -9585,6 +10214,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); + DiagnoseMisalignedMembers(); } void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, @@ -9695,6 +10325,19 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, return HasInvalidParm; } +/// A helper function to get the alignment of a Decl referred to by DeclRefExpr +/// or MemberExpr. +static CharUnits getDeclAlign(Expr *E, CharUnits TypeAlign, + ASTContext &Context) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + return Context.getDeclAlign(DRE->getDecl()); + + if (const auto *ME = dyn_cast<MemberExpr>(E)) + return Context.getDeclAlign(ME->getMemberDecl()); + + return TypeAlign; +} + /// CheckCastAlign - Implements -Wcast-align, which warns when a /// pointer cast increases the alignment requirements. void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { @@ -9729,6 +10372,15 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { if (SrcPointee->isIncompleteType()) return; CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee); + + if (auto *CE = dyn_cast<CastExpr>(Op)) { + if (CE->getCastKind() == CK_ArrayToPointerDecay) + SrcAlign = getDeclAlign(CE->getSubExpr(), SrcAlign, Context); + } else if (auto *UO = dyn_cast<UnaryOperator>(Op)) { + if (UO->getOpcode() == UO_AddrOf) + SrcAlign = getDeclAlign(UO->getSubExpr(), SrcAlign, Context); + } + if (SrcAlign >= DestAlign) return; Diag(TRange.getBegin(), diag::warn_cast_align) @@ -11130,3 +11782,151 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } + +void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment) { + MisalignedMembers.emplace_back(E, RD, MD, Alignment); +} + +void Sema::DiagnoseMisalignedMembers() { + for (MisalignedMember &m : MisalignedMembers) { + const NamedDecl *ND = m.RD; + if (ND->getName().empty()) { + if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl()) + ND = TD; + } + Diag(m.E->getLocStart(), diag::warn_taking_address_of_packed_member) + << m.MD << ND << m.E->getSourceRange(); + } + MisalignedMembers.clear(); +} + +void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { + E = E->IgnoreParens(); + if (!T->isPointerType() && !T->isIntegerType()) + return; + if (isa<UnaryOperator>(E) && + cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { + auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); + if (isa<MemberExpr>(Op)) { + auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), + MisalignedMember(Op)); + if (MA != MisalignedMembers.end() && + (T->isIntegerType() || + (T->isPointerType() && + Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment))) + MisalignedMembers.erase(MA); + } + } +} + +void Sema::RefersToMemberWithReducedAlignment( + Expr *E, + llvm::function_ref<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)> + Action) { + const auto *ME = dyn_cast<MemberExpr>(E); + if (!ME) + return; + + // For a chain of MemberExpr like "a.b.c.d" this list + // will keep FieldDecl's like [d, c, b]. + SmallVector<FieldDecl *, 4> ReverseMemberChain; + const MemberExpr *TopME = nullptr; + bool AnyIsPacked = false; + do { + QualType BaseType = ME->getBase()->getType(); + if (ME->isArrow()) + BaseType = BaseType->getPointeeType(); + RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + + ValueDecl *MD = ME->getMemberDecl(); + auto *FD = dyn_cast<FieldDecl>(MD); + // We do not care about non-data members. + if (!FD || FD->isInvalidDecl()) + return; + + AnyIsPacked = + AnyIsPacked || (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>()); + ReverseMemberChain.push_back(FD); + + TopME = ME; + ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParens()); + } while (ME); + assert(TopME && "We did not compute a topmost MemberExpr!"); + + // Not the scope of this diagnostic. + if (!AnyIsPacked) + return; + + const Expr *TopBase = TopME->getBase()->IgnoreParenImpCasts(); + const auto *DRE = dyn_cast<DeclRefExpr>(TopBase); + // TODO: The innermost base of the member expression may be too complicated. + // For now, just disregard these cases. This is left for future + // improvement. + if (!DRE && !isa<CXXThisExpr>(TopBase)) + return; + + // Alignment expected by the whole expression. + CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType()); + + // No need to do anything else with this case. + if (ExpectedAlignment.isOne()) + return; + + // Synthesize offset of the whole access. + CharUnits Offset; + for (auto I = ReverseMemberChain.rbegin(); I != ReverseMemberChain.rend(); + I++) { + Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(*I)); + } + + // Compute the CompleteObjectAlignment as the alignment of the whole chain. + CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars( + ReverseMemberChain.back()->getParent()->getTypeForDecl()); + + // The base expression of the innermost MemberExpr may give + // stronger guarantees than the class containing the member. + if (DRE && !TopME->isArrow()) { + const ValueDecl *VD = DRE->getDecl(); + if (!VD->getType()->isReferenceType()) + CompleteObjectAlignment = + std::max(CompleteObjectAlignment, Context.getDeclAlign(VD)); + } + + // Check if the synthesized offset fulfills the alignment. + if (Offset % ExpectedAlignment != 0 || + // It may fulfill the offset it but the effective alignment may still be + // lower than the expected expression alignment. + CompleteObjectAlignment < ExpectedAlignment) { + // If this happens, we want to determine a sensible culprit of this. + // Intuitively, watching the chain of member expressions from right to + // left, we start with the required alignment (as required by the field + // type) but some packed attribute in that chain has reduced the alignment. + // It may happen that another packed structure increases it again. But if + // we are here such increase has not been enough. So pointing the first + // FieldDecl that either is packed or else its RecordDecl is, + // seems reasonable. + FieldDecl *FD = nullptr; + CharUnits Alignment; + for (FieldDecl *FDI : ReverseMemberChain) { + if (FDI->hasAttr<PackedAttr>() || + FDI->getParent()->hasAttr<PackedAttr>()) { + FD = FDI; + Alignment = std::min( + Context.getTypeAlignInChars(FD->getType()), + Context.getTypeAlignInChars(FD->getParent()->getTypeForDecl())); + break; + } + } + assert(FD && "We did not find a packed FieldDecl!"); + Action(E, FD->getParent(), FD, Alignment); + } +} + +void Sema::CheckAddressOfPackedMember(Expr *rhs) { + using namespace std::placeholders; + RefersToMemberWithReducedAlignment( + rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, + _2, _3, _4)); +} + |