diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 403 |
1 files changed, 257 insertions, 146 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 79420cc27699..aed1d9befe2b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -109,6 +109,11 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, Context.getTargetInfo()); } +static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A, + Sema::FormatArgumentPassingKind B) { + return (A << 8) | B; +} + /// Checks that a call expression's argument count is at least the desired /// number. This is useful when doing custom type-checking on a variadic /// function. Returns true on error. @@ -1875,7 +1880,7 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) { }(); if (DiagSelect) { S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg) - << DiagSelect.getValue() << TheCall->getSourceRange(); + << DiagSelect.value() << TheCall->getSourceRange(); return ExprError(); } @@ -2408,7 +2413,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, bool ReturnsPointer = BuiltinID == Builtin::BIaddressof || BuiltinID == Builtin::BI__addressof; if (!(Param->isReferenceType() && - (ReturnsPointer ? Result->isPointerType() + (ReturnsPointer ? Result->isAnyPointerType() : Result->isReferenceType()) && Context.hasSameUnqualifiedType(Param->getPointeeType(), Result->getPointeeType()))) { @@ -5403,10 +5408,16 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, /// Returns true when the format fits the function and the FormatStringInfo has /// been populated. bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, - FormatStringInfo *FSI) { - FSI->HasVAListArg = Format->getFirstArg() == 0; + bool IsVariadic, FormatStringInfo *FSI) { + if (Format->getFirstArg() == 0) + FSI->ArgPassingKind = FAPK_VAList; + else if (IsVariadic) + FSI->ArgPassingKind = FAPK_Variadic; + else + FSI->ArgPassingKind = FAPK_Fixed; FSI->FormatIdx = Format->getFormatIdx() - 1; - FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1; + FSI->FirstDataArg = + FSI->ArgPassingKind == FAPK_VAList ? 0 : Format->getFirstArg() - 1; // The way the format attribute works in GCC, the implicit this argument // of member functions is counted. However, it doesn't appear in our own @@ -5461,7 +5472,7 @@ static void CheckNonNullArgument(Sema &S, bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { FormatStringInfo FSI; if ((GetFormatStringType(Format) == FST_NSString) && - getFormatStringInfo(Format, false, &FSI)) { + getFormatStringInfo(Format, false, true, &FSI)) { Idx = FSI.FormatIdx; return true; } @@ -5615,6 +5626,40 @@ static void CheckNonNullArguments(Sema &S, } } +// 16 byte ByVal alignment not due to a vector member is not honoured by XL +// on AIX. Emit a warning here that users are generating binary incompatible +// code to be safe. +// Here we try to get information about the alignment of the struct member +// from the struct passed to the caller function. We only warn when the struct +// is passed byval, hence the series of checks and early returns if we are a not +// passing a struct byval. +void Sema::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { + const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg->IgnoreParens()); + if (!ICE) + return; + + const auto *DR = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); + if (!DR) + return; + + const auto *PD = dyn_cast<ParmVarDecl>(DR->getDecl()); + if (!PD || !PD->getType()->isRecordType()) + return; + + QualType ArgType = Arg->getType(); + for (const FieldDecl *FD : + ArgType->castAs<RecordType>()->getDecl()->fields()) { + if (const auto *AA = FD->getAttr<AlignedAttr>()) { + CharUnits Alignment = + Context.toCharUnitsFromBits(AA->getAlignment(Context)); + if (Alignment.getQuantity() == 16) { + Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD; + Diag(Loc, diag::note_misaligned_member_used_here) << PD; + } + } + } +} + /// Warn if a pointer or reference argument passed to a function points to an /// object that is less aligned than the parameter. This can happen when /// creating a typedef with a lower alignment than the original type and then @@ -5725,6 +5770,12 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, if (Arg->containsErrors()) continue; + if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg && + FDecl->hasLinkage() && + FDecl->getFormalLinkage() != InternalLinkage && + CallType == VariadicDoesNotApply) + checkAIXMemberAlignment((Arg->getExprLoc()), Arg); + QualType ParamTy = Proto->getParamType(ArgIdx); QualType ArgTy = Arg->getType(); CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1), @@ -7695,7 +7746,7 @@ bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { llvm::SmallBitVector CheckedVarArgs(NumArgs, false); ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs()); bool Success = CheckFormatArguments( - Args, /*HasVAListArg*/ false, FormatIdx, FirstDataArg, FST_OSLog, + Args, FAPK_Variadic, FormatIdx, FirstDataArg, FST_OSLog, VariadicFunction, TheCall->getBeginLoc(), SourceRange(), CheckedVarArgs); if (!Success) @@ -8412,19 +8463,15 @@ class FormatStringLiteral { SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getEndLoc(); } }; -} // namespace +} // namespace -static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, - const Expr *OrigFormatExpr, - ArrayRef<const Expr *> Args, - bool HasVAListArg, unsigned format_idx, - unsigned firstDataArg, - Sema::FormatStringType Type, - bool inFunctionCall, - Sema::VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg, - bool IgnoreStringsWithoutSpecifiers); +static void CheckFormatString( + Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK, + unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, + bool inFunctionCall, Sema::VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, + bool IgnoreStringsWithoutSpecifiers); // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a @@ -8432,16 +8479,15 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, // True string literals are then checked by CheckFormatString. static StringLiteralCheckType checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, - bool HasVAListArg, unsigned format_idx, + Sema::FormatArgumentPassingKind APK, unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, Sema::VariadicCallType CallType, bool InFunctionCall, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg, - llvm::APSInt Offset, + UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset, bool IgnoreStringsWithoutSpecifiers = false) { if (S.isConstantEvaluated()) return SLCT_NotALiteral; - tryAgain: +tryAgain: assert(Offset.isSigned() && "invalid offset"); if (E->isTypeDependent() || E->isValueDependent()) @@ -8486,9 +8532,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, if (!CheckLeft) Left = SLCT_UncheckedLiteral; else { - Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, + Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, APK, format_idx, + firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); if (Left == SLCT_NotALiteral || !CheckRight) { @@ -8497,8 +8542,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, } StringLiteralCheckType Right = checkFormatStringExpr( - S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + S, C->getFalseExpr(), Args, APK, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); return (CheckLeft && Left < Right) ? Left : Right; @@ -8548,42 +8593,85 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, if (InitList->isStringLiteralInit()) Init = InitList->getInit(0)->IgnoreParenImpCasts(); } - return checkFormatStringExpr(S, Init, Args, - HasVAListArg, format_idx, - firstDataArg, Type, CallType, - /*InFunctionCall*/ false, CheckedVarArgs, - UncoveredArg, Offset); + return checkFormatStringExpr( + S, Init, Args, APK, format_idx, firstDataArg, Type, CallType, + /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, Offset); } } - // For vprintf* functions (i.e., HasVAListArg==true), we add a - // special check to see if the format string is a function parameter - // of the function calling the printf function. If the function - // has an attribute indicating it is a printf-like function, then we - // should suppress warnings concerning non-literals being used in a call - // to a vprintf function. For example: + // When the format argument is an argument of this function, and this + // function also has the format attribute, there are several interactions + // for which there shouldn't be a warning. For instance, when calling + // v*printf from a function that has the printf format attribute, we + // should not emit a warning about using `fmt`, even though it's not + // constant, because the arguments have already been checked for the + // caller of `logmessage`: // - // void - // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...){ - // va_list ap; - // va_start(ap, fmt); - // vprintf(fmt, ap); // Do NOT emit a warning about "fmt". - // ... + // __attribute__((format(printf, 1, 2))) + // void logmessage(char const *fmt, ...) { + // va_list ap; + // va_start(ap, fmt); + // vprintf(fmt, ap); /* do not emit a warning about "fmt" */ + // ... // } - if (HasVAListArg) { - if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) { - if (const Decl *D = dyn_cast<Decl>(PV->getDeclContext())) { - int PVIndex = PV->getFunctionScopeIndex() + 1; - for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) { - // adjust for implicit parameter - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) - if (MD->isInstance()) - ++PVIndex; + // + // Another interaction that we need to support is calling a variadic + // format function from a format function that has fixed arguments. For + // instance: + // + // __attribute__((format(printf, 1, 2))) + // void logstring(char const *fmt, char const *str) { + // printf(fmt, str); /* do not emit a warning about "fmt" */ + // } + // + // Same (and perhaps more relatably) for the variadic template case: + // + // template<typename... Args> + // __attribute__((format(printf, 1, 2))) + // void log(const char *fmt, Args&&... args) { + // printf(fmt, forward<Args>(args)...); + // /* do not emit a warning about "fmt" */ + // } + // + // Due to implementation difficulty, we only check the format, not the + // format arguments, in all cases. + // + if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) { + if (const auto *D = dyn_cast<Decl>(PV->getDeclContext())) { + for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) { + bool IsCXXMember = false; + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) + IsCXXMember = MD->isInstance(); + + bool IsVariadic = false; + if (const FunctionType *FnTy = D->getFunctionType()) + IsVariadic = cast<FunctionProtoType>(FnTy)->isVariadic(); + else if (const auto *BD = dyn_cast<BlockDecl>(D)) + IsVariadic = BD->isVariadic(); + else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D)) + IsVariadic = OMD->isVariadic(); + + Sema::FormatStringInfo CallerFSI; + if (Sema::getFormatStringInfo(PVFormat, IsCXXMember, IsVariadic, + &CallerFSI)) { // We also check if the formats are compatible. // We can't pass a 'scanf' string to a 'printf' function. - if (PVIndex == PVFormat->getFormatIdx() && - Type == S.GetFormatStringType(PVFormat)) - return SLCT_UncheckedLiteral; + if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx && + Type == S.GetFormatStringType(PVFormat)) { + // Lastly, check that argument passing kinds transition in a + // way that makes sense: + // from a caller with FAPK_VAList, allow FAPK_VAList + // from a caller with FAPK_Fixed, allow FAPK_Fixed + // from a caller with FAPK_Fixed, allow FAPK_Variadic + // from a caller with FAPK_Variadic, allow FAPK_VAList + switch (combineFAPK(CallerFSI.ArgPassingKind, APK)) { + case combineFAPK(Sema::FAPK_VAList, Sema::FAPK_VAList): + case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Fixed): + case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Variadic): + case combineFAPK(Sema::FAPK_Variadic, Sema::FAPK_VAList): + return SLCT_UncheckedLiteral; + } + } } } } @@ -8602,8 +8690,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); StringLiteralCheckType Result = checkFormatStringExpr( - S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, - CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType, + InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); if (IsFirst) { CommonResult = Result; @@ -8618,12 +8706,10 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { const Expr *Arg = CE->getArg(0); - return checkFormatStringExpr(S, Arg, Args, - HasVAListArg, format_idx, - firstDataArg, Type, CallType, - InFunctionCall, CheckedVarArgs, - UncoveredArg, Offset, - IgnoreStringsWithoutSpecifiers); + return checkFormatStringExpr( + S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType, + InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); } } } @@ -8651,8 +8737,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); return checkFormatStringExpr( - S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, - CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, + S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType, + InFunctionCall, CheckedVarArgs, UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers); } } @@ -8675,9 +8761,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return SLCT_NotALiteral; } FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue()); - CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx, - firstDataArg, Type, InFunctionCall, CallType, - CheckedVarArgs, UncoveredArg, + CheckFormatString(S, &FStr, E, Args, APK, format_idx, firstDataArg, Type, + InFunctionCall, CallType, CheckedVarArgs, UncoveredArg, IgnoreStringsWithoutSpecifiers); return SLCT_CheckedLiteral; } @@ -8756,24 +8841,25 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { /// functions) for correct use of format strings. /// Returns true if a format string has been fully checked. bool Sema::CheckFormatArguments(const FormatAttr *Format, - ArrayRef<const Expr *> Args, - bool IsCXXMember, - VariadicCallType CallType, - SourceLocation Loc, SourceRange Range, + ArrayRef<const Expr *> Args, bool IsCXXMember, + VariadicCallType CallType, SourceLocation Loc, + SourceRange Range, llvm::SmallBitVector &CheckedVarArgs) { FormatStringInfo FSI; - if (getFormatStringInfo(Format, IsCXXMember, &FSI)) - return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx, + if (getFormatStringInfo(Format, IsCXXMember, CallType != VariadicDoesNotApply, + &FSI)) + return CheckFormatArguments(Args, FSI.ArgPassingKind, FSI.FormatIdx, FSI.FirstDataArg, GetFormatStringType(Format), CallType, Loc, Range, CheckedVarArgs); return false; } bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, - bool HasVAListArg, unsigned format_idx, - unsigned firstDataArg, FormatStringType Type, - VariadicCallType CallType, - SourceLocation Loc, SourceRange Range, + Sema::FormatArgumentPassingKind APK, + unsigned format_idx, unsigned firstDataArg, + FormatStringType Type, + VariadicCallType CallType, SourceLocation Loc, + SourceRange Range, llvm::SmallBitVector &CheckedVarArgs) { // CHECK: printf/scanf-like function is called with no format string. if (format_idx >= Args.size()) { @@ -8796,12 +8882,11 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. UncoveredArgHandler UncoveredArg; - StringLiteralCheckType CT = - checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg, - format_idx, firstDataArg, Type, CallType, - /*IsFunctionCall*/ true, CheckedVarArgs, - UncoveredArg, - /*no string offset*/ llvm::APSInt(64, false) = 0); + StringLiteralCheckType CT = checkFormatStringExpr( + *this, OrigFormatExpr, Args, APK, format_idx, firstDataArg, Type, + CallType, + /*IsFunctionCall*/ true, CheckedVarArgs, UncoveredArg, + /*no string offset*/ llvm::APSInt(64, false) = 0); // Generate a diagnostic where an uncovered argument is detected. if (UncoveredArg.hasUncoveredArg()) { @@ -8864,7 +8949,7 @@ protected: const unsigned FirstDataArg; const unsigned NumDataArgs; const char *Beg; // Start of format string. - const bool HasVAListArg; + const Sema::FormatArgumentPassingKind ArgPassingKind; ArrayRef<const Expr *> Args; unsigned FormatIdx; llvm::SmallBitVector CoveredArgs; @@ -8879,14 +8964,15 @@ public: CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr, const Expr *origFormatExpr, const Sema::FormatStringType type, unsigned firstDataArg, - unsigned numDataArgs, const char *beg, bool hasVAListArg, + unsigned numDataArgs, const char *beg, + Sema::FormatArgumentPassingKind APK, ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType callType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), - HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), + ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx), inFunctionCall(inFunctionCall), CallType(callType), CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); @@ -9122,8 +9208,8 @@ const Expr *CheckFormatHandler::getDataArg(unsigned i) const { void CheckFormatHandler::DoneProcessing() { // Does the number of data arguments exceed the number of // format conversions in the format string? - if (!HasVAListArg) { - // Find any arguments that weren't covered. + if (ArgPassingKind != Sema::FAPK_VAList) { + // Find any arguments that weren't covered. CoveredArgs.flip(); signed notCoveredArg = CoveredArgs.find_first(); if (notCoveredArg >= 0) { @@ -9318,13 +9404,13 @@ public: 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, + Sema::FormatArgumentPassingKind APK, + ArrayRef<const Expr *> Args, unsigned formatIdx, + bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, - numDataArgs, beg, hasVAListArg, Args, formatIdx, + numDataArgs, beg, APK, Args, formatIdx, inFunctionCall, CallType, CheckedVarArgs, UncoveredArg) {} @@ -9399,17 +9485,16 @@ void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) { } bool CheckPrintfHandler::HandleAmount( - const analyze_format_string::OptionalAmount &Amt, - unsigned k, const char *startSpecifier, - unsigned specifierLen) { + const analyze_format_string::OptionalAmount &Amt, unsigned k, + const char *startSpecifier, unsigned specifierLen) { if (Amt.hasDataArgument()) { - if (!HasVAListArg) { + if (ArgPassingKind != Sema::FAPK_VAList) { unsigned argIndex = Amt.getArgIndex(); if (argIndex >= NumDataArgs) { EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg) - << k, + << k, getLocationOfByte(Amt.getStart()), - /*IsStringLocation*/true, + /*IsStringLocation*/ true, getSpecifierRange(startSpecifier, specifierLen)); // Don't do any more checking. We will just emit // spurious errors. @@ -9805,7 +9890,7 @@ bool CheckPrintfHandler::HandlePrintfSpecifier( HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); // The remaining checks depend on the data arguments. - if (HasVAListArg) + if (ArgPassingKind == Sema::FAPK_VAList) return true; if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) @@ -9953,6 +10038,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } + // When using the format attribute in C++, you can receive a function or an + // array that will necessarily decay to a pointer when passed to the final + // format consumer. Apply decay before type comparison. + if (ExprTy->canDecayToPointerType()) + ExprTy = S.Context.getDecayedType(ExprTy); + // Diagnose attempts to print a boolean value as a character. Unlike other // -Wformat diagnostics, this is fine from a type perspective, but it still // doesn't make sense. @@ -10173,6 +10264,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // Since the warning for passing non-POD types to variadic functions // was deferred until now, we emit a warning for non-POD // arguments here. + bool EmitTypeMismatch = false; switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { @@ -10198,17 +10290,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, } case Sema::VAK_Undefined: case Sema::VAK_MSVCUndefined: - EmitFormatDiagnostic(S.PDiag(diag::warn_non_pod_vararg_with_format_string) - << S.getLangOpts().CPlusPlus11 << ExprTy - << CallType - << AT.getRepresentativeTypeName(S.Context) << CSR - << E->getSourceRange(), - E->getBeginLoc(), /*IsStringLocation*/ false, CSR); - checkForCStrMembers(AT, E); + if (CallType == Sema::VariadicDoesNotApply) { + EmitTypeMismatch = true; + } else { + EmitFormatDiagnostic( + S.PDiag(diag::warn_non_pod_vararg_with_format_string) + << S.getLangOpts().CPlusPlus11 << ExprTy << CallType + << AT.getRepresentativeTypeName(S.Context) << CSR + << E->getSourceRange(), + E->getBeginLoc(), /*IsStringLocation*/ false, CSR); + checkForCStrMembers(AT, E); + } break; case Sema::VAK_Invalid: - if (ExprTy->isObjCObjectType()) + if (CallType == Sema::VariadicDoesNotApply) + EmitTypeMismatch = true; + else if (ExprTy->isObjCObjectType()) EmitFormatDiagnostic( S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format) << S.getLangOpts().CPlusPlus11 << ExprTy << CallType @@ -10224,6 +10322,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, break; } + if (EmitTypeMismatch) { + // The function is not variadic, so we do not generate warnings about + // being allowed to pass that object as a variadic argument. Instead, + // since there are inherently no printf specifiers for types which cannot + // be passed as variadic arguments, emit a plain old specifier mismatch + // argument. + EmitFormatDiagnostic( + S.PDiag(diag::warn_format_conversion_argument_type_mismatch) + << AT.getRepresentativeTypeName(S.Context) << ExprTy << false + << E->getSourceRange(), + E->getBeginLoc(), false, CSR); + } + assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() && "format string specifier index out of range"); CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true; @@ -10241,13 +10352,13 @@ public: CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, const Expr *origFormatExpr, Sema::FormatStringType type, unsigned firstDataArg, unsigned numDataArgs, - const char *beg, bool hasVAListArg, + const char *beg, Sema::FormatArgumentPassingKind APK, ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, - numDataArgs, beg, hasVAListArg, Args, formatIdx, + numDataArgs, beg, APK, Args, formatIdx, inFunctionCall, CallType, CheckedVarArgs, UncoveredArg) {} @@ -10351,7 +10462,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); // The remaining checks depend on the data arguments. - if (HasVAListArg) + if (ArgPassingKind == Sema::FAPK_VAList) return true; if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) @@ -10408,17 +10519,13 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } -static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, - const Expr *OrigFormatExpr, - ArrayRef<const Expr *> Args, - bool HasVAListArg, unsigned format_idx, - unsigned firstDataArg, - Sema::FormatStringType Type, - bool inFunctionCall, - Sema::VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg, - bool IgnoreStringsWithoutSpecifiers) { +static void CheckFormatString( + Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK, + unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, + bool inFunctionCall, Sema::VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, + bool IgnoreStringsWithoutSpecifiers) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { CheckFormatHandler::EmitFormatDiagnostic( @@ -10469,23 +10576,21 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, 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(), - S.Context.getTargetInfo(), - Type == Sema::FST_FreeBSDKPrintf)) + (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, APK, + Args, format_idx, inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); + + if (!analyze_format_string::ParsePrintfString( + H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(), + Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); } else if (Type == Sema::FST_Scanf) { CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, - numDataArgs, Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs, UncoveredArg); + numDataArgs, Str, APK, Args, format_idx, inFunctionCall, + CallType, CheckedVarArgs, UncoveredArg); - if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, - S.getLangOpts(), - S.Context.getTargetInfo())) + if (!analyze_format_string::ParseScanfString( + H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo())) H.DoneProcessing(); } // TODO: handle other formats } @@ -16765,9 +16870,15 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, RHSDeclRef->getDecl()->getCanonicalDecl()) return; - Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() - << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); + auto D = Diag(OpLoc, diag::warn_self_move) + << LHSExpr->getType() << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); + if (const FieldDecl *F = + getSelfAssignmentClassMemberCandidate(RHSDeclRef->getDecl())) + D << 1 << F + << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->"); + else + D << 0; return; } @@ -16802,16 +16913,16 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, RHSDeclRef->getDecl()->getCanonicalDecl()) return; - Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() - << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); + Diag(OpLoc, diag::warn_self_move) + << LHSExpr->getType() << 0 << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); return; } if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase)) - Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() - << LHSExpr->getSourceRange() - << RHSExpr->getSourceRange(); + Diag(OpLoc, diag::warn_self_move) + << LHSExpr->getType() << 0 << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); } //===--- Layout compatibility ----------------------------------------------// |
