inclyc updated this revision to Diff 450528.
inclyc added a comment.
Use isa<> to check Expr class
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D131314/new/
https://reviews.llvm.org/D131314
Files:
clang/lib/Sema/SemaChecking.cpp
clang/test/SemaCXX/format-strings.cpp
Index: clang/test/SemaCXX/format-strings.cpp
===================================================================
--- clang/test/SemaCXX/format-strings.cpp
+++ clang/test/SemaCXX/format-strings.cpp
@@ -166,6 +166,14 @@
#if __cplusplus >= 201103L
namespace evaluated {
+struct InitList {
+ static constexpr char value[] = {'%', 's', '%', 'd', '\0'}; // no note here because this is not literal
+};
+
+constexpr const char *init_list_func() { return InitList::value; }
+
+constexpr const char *init_list_func_wrap() { return init_list_func(); }
+
constexpr const char *basic() {
return
"%s %d"; // expected-note {{format string is defined here}}
@@ -199,12 +207,15 @@
void f() {
printf(basic(), 1, 2); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
- printf(correct_fmt(), 1, 2);
+ printf(correct_fmt(), 1, 2); // no warning
printf(string_linebreak(), 1, 2, 3, 4); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
printf(not_literal(), 1, 2, 3, 4); // expected-warning {{format string is not a string literal}}
printf(wrap_constexpr(), 1, 2); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
+ printf(InitList::value, 1, 2); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
+ printf(init_list_func(), 1, 2); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
+ printf(init_list_func_wrap(), 1, 2); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}}
}
-}
+} // namespace evaluated
#endif
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -8469,25 +8469,26 @@
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,
+ bool NoNote, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
bool IgnoreStringsWithoutSpecifiers);
-static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
- const Expr *E);
-
-// Determine if an expression is a string literal or constant string.
-// If this function returns false on the arguments to a function expecting a
-// format string, we will usually need to emit a warning.
-// True string literals are then checked by CheckFormatString.
static StringLiteralCheckType
-checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
- Sema::FormatArgumentPassingKind APK, unsigned format_idx,
- unsigned firstDataArg, Sema::FormatStringType Type,
- Sema::VariadicCallType CallType, bool InFunctionCall,
- llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset,
- bool IgnoreStringsWithoutSpecifiers = false) {
+checkVarDecl(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
+ Sema::FormatArgumentPassingKind APK, unsigned format_idx,
+ unsigned firstDataArg, Sema::FormatStringType Type,
+ Sema::VariadicCallType CallType, bool NoNote,
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset, QualType T,
+ const VarDecl *VD, bool IgnoreStringsWithoutSpecifiers);
+
+static StringLiteralCheckType checkFormatStringExprEvaluated(
+ Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
+ Sema::FormatArgumentPassingKind APK, unsigned format_idx,
+ unsigned firstDataArg, Sema::FormatStringType Type,
+ Sema::VariadicCallType CallType, bool NoNote,
+ llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+ llvm::APSInt Offset, bool IgnoreStringsWithoutSpecifiers = false) {
if (S.isConstantEvaluated())
return SLCT_NotALiteral;
tryAgain:
@@ -8510,8 +8511,7 @@
case Stmt::ConditionalOperatorClass: {
// The expression is a literal if both sub-expressions were, and it was
// completely checked only if both sub-expressions were checked.
- const AbstractConditionalOperator *C =
- cast<AbstractConditionalOperator>(E);
+ const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
// Determine whether it is necessary to check both sub-expressions, for
// example, because the condition expression is a constant that can be
@@ -8535,18 +8535,18 @@
if (!CheckLeft)
Left = SLCT_UncheckedLiteral;
else {
- Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, APK, format_idx,
- firstDataArg, Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset,
- IgnoreStringsWithoutSpecifiers);
+ Left = checkFormatStringExprEvaluated(
+ S, C->getTrueExpr(), Args, APK, format_idx, firstDataArg, Type,
+ CallType, NoNote, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
if (Left == SLCT_NotALiteral || !CheckRight) {
return Left;
}
}
- StringLiteralCheckType Right = checkFormatStringExpr(
+ StringLiteralCheckType Right = checkFormatStringExprEvaluated(
S, C->getFalseExpr(), Args, APK, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ CallType, NoNote, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
return (CheckLeft && Left < Right) ? Left : Right;
@@ -8575,110 +8575,10 @@
// As an exception, do not flag errors for variables binding to
// const string literals.
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- bool isConstant = false;
- QualType T = DR->getType();
-
- if (const ArrayType *AT = S.Context.getAsArrayType(T)) {
- isConstant = AT->getElementType().isConstant(S.Context);
- } else if (const PointerType *PT = T->getAs<PointerType>()) {
- isConstant = T.isConstant(S.Context) &&
- PT->getPointeeType().isConstant(S.Context);
- } else if (T->isObjCObjectPointerType()) {
- // In ObjC, there is usually no "const ObjectPointer" type,
- // so don't check if the pointee type is constant.
- isConstant = T.isConstant(S.Context);
- }
-
- if (isConstant) {
- if (const Expr *Init = VD->getAnyInitializer()) {
- // Look through initializers like const char c[] = { "foo" }
- if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
- if (InitList->isStringLiteralInit())
- Init = InitList->getInit(0)->IgnoreParenImpCasts();
- }
- return checkFormatStringExpr(
- S, Init, Args, APK, format_idx, firstDataArg, Type, CallType,
- /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, Offset);
- }
- }
-
- // When the format argument is an argument of this function, and this
- // function also has the format attribute, there are several interactions
- // for which there shouldn't be a warning. For instance, when calling
- // v*printf from a function that has the printf format attribute, we
- // should not emit a warning about using `fmt`, even though it's not
- // constant, because the arguments have already been checked for the
- // caller of `logmessage`:
- //
- // __attribute__((format(printf, 1, 2)))
- // void logmessage(char const *fmt, ...) {
- // va_list ap;
- // va_start(ap, fmt);
- // vprintf(fmt, ap); /* do not emit a warning about "fmt" */
- // ...
- // }
- //
- // Another interaction that we need to support is 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 (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;
- }
- }
- }
- }
- }
- }
+ return checkVarDecl(S, E, Args, APK, format_idx, firstDataArg, Type,
+ CallType, NoNote, CheckedVarArgs, UncoveredArg,
+ Offset, DR->getType(), VD,
+ IgnoreStringsWithoutSpecifiers);
}
return SLCT_NotALiteral;
@@ -8687,14 +8587,15 @@
case Stmt::CallExprClass:
case Stmt::CXXMemberCallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
- if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
+ if (const NamedDecl *ND =
+ dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
bool IsFirst = true;
StringLiteralCheckType CommonResult;
for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
- StringLiteralCheckType Result = checkFormatStringExpr(
- S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ StringLiteralCheckType Result = checkFormatStringExprEvaluated(
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType, NoNote,
+ CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
if (IsFirst) {
CommonResult = Result;
@@ -8709,18 +8610,13 @@
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(
+ return checkFormatStringExprEvaluated(
S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ NoNote, CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
}
}
}
- if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E))
- return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg,
- Type, CallType, /*InFunctionCall*/ false,
- CheckedVarArgs, UncoveredArg, Offset,
- IgnoreStringsWithoutSpecifiers);
return SLCT_NotALiteral;
}
case Stmt::ObjCMessageExprClass: {
@@ -8743,9 +8639,9 @@
}
const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
- return checkFormatStringExpr(
- S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ return checkFormatStringExprEvaluated(
+ S, Arg, Args, APK, format_idx, firstDataArg, Type, CallType, NoNote,
+ CheckedVarArgs, UncoveredArg, Offset,
IgnoreStringsWithoutSpecifiers);
}
}
@@ -8769,13 +8665,58 @@
}
FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
CheckFormatString(S, &FStr, E, Args, APK, format_idx, firstDataArg, Type,
- InFunctionCall, CallType, CheckedVarArgs, UncoveredArg,
+ NoNote, CallType, CheckedVarArgs, UncoveredArg,
IgnoreStringsWithoutSpecifiers);
return SLCT_CheckedLiteral;
}
return SLCT_NotALiteral;
}
+
+ case Stmt::InitListExprClass: {
+ auto *ILE = cast<InitListExpr>(E);
+ if (ILE->isStringLiteralInit()) {
+ auto *SL =
+ dyn_cast<StringLiteral>(ILE->getInit(0)->IgnoreParenImpCasts());
+ return checkFormatStringExprEvaluated(
+ S, SL, Args, APK, format_idx, firstDataArg, Type, CallType, NoNote,
+ CheckedVarArgs, UncoveredArg, Offset);
+ }
+ // looks like {'a', 'b', 'c'}
+ ArrayRef<clang::Expr *> AR = ILE->inits();
+ SmallString<128> StrBuf;
+ QualType Ty;
+ bool HasCStringEnd = false;
+ for (auto &Expr : AR) {
+ if (isa<CharacterLiteral>(Expr)) {
+ const auto *CL = cast<const CharacterLiteral>(Expr);
+ // construct a StringRef for this
+ unsigned int CharacterValue = CL->getValue();
+ if (CharacterValue == 0) {
+ HasCStringEnd = true;
+ break;
+ }
+ StrBuf.push_back(CharacterValue);
+ Ty = Expr->getType();
+ } else {
+ // not a CharacterLiteral
+ return SLCT_NotALiteral;
+ }
+ }
+ if (!HasCStringEnd) {
+ // FIXME: fire a warning that this InitListExprClass does not end with
+ // '\0', with FixIt hints
+ }
+ const auto SR = StringRef(StrBuf);
+ const auto *SL = StringLiteral::Create(
+ S.Context, SR, StringLiteral::Ordinary,
+ /*Pascal*/ false, S.Context.getStringLiteralArrayType(Ty, SR.size()),
+ SourceLocation());
+ return checkFormatStringExprEvaluated(
+ S, SL, Args, APK, format_idx, firstDataArg, Type, CallType,
+ /*NoNote*/ true, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
+ }
case Stmt::BinaryOperatorClass: {
const BinaryOperator *BinOp = cast<BinaryOperator>(E);
@@ -8830,18 +8771,158 @@
}
}
-// If this expression can be evaluated at compile-time,
-// check if the result is a StringLiteral and return it
-// otherwise return nullptr
-static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
- const Expr *E) {
- Expr::EvalResult Result;
- if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
- const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
- if (isa_and_nonnull<StringLiteral>(LVE))
- return LVE;
+static StringLiteralCheckType
+checkVarDecl(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
+ Sema::FormatArgumentPassingKind APK, unsigned format_idx,
+ unsigned firstDataArg, Sema::FormatStringType Type,
+ Sema::VariadicCallType CallType, bool NoNote,
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset, QualType T,
+ const VarDecl *VD, bool IgnoreStringsWithoutSpecifiers) {
+ bool isConstant = false;
+
+ if (const ArrayType *AT = S.Context.getAsArrayType(T)) {
+ isConstant = AT->getElementType().isConstant(S.Context);
+ } else if (const PointerType *PT = T->getAs<PointerType>()) {
+ isConstant =
+ T.isConstant(S.Context) && PT->getPointeeType().isConstant(S.Context);
+ } else if (T->isObjCObjectPointerType()) {
+ // In ObjC, there is usually no "const ObjectPointer" type,
+ // so don't check if the pointee type is constant.
+ isConstant = T.isConstant(S.Context);
+ }
+
+ if (isConstant) {
+ if (const Expr *Init = VD->getAnyInitializer()) {
+ // Look through initializers like const char c[] = { "foo" }
+ if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
+ if (InitList->isStringLiteralInit())
+ Init = InitList->getInit(0)->IgnoreParenImpCasts();
+ }
+ return checkFormatStringExprEvaluated(
+ S, Init, Args, APK, format_idx, firstDataArg, Type, CallType,
+ /*NoNote*/ false, CheckedVarArgs, UncoveredArg, Offset);
+ }
}
- return nullptr;
+
+ // When the format argument is an argument of this function, and this
+ // function also has the format attribute, there are several interactions
+ // for which there shouldn't be a warning. For instance, when calling
+ // v*printf from a function that has the printf format attribute, we
+ // should not emit a warning about using `fmt`, even though it's not
+ // constant, because the arguments have already been checked for the
+ // caller of `logmessage`:
+ //
+ // __attribute__((format(printf, 1, 2)))
+ // void logmessage(char const *fmt, ...) {
+ // va_list ap;
+ // va_start(ap, fmt);
+ // vprintf(fmt, ap); /* do not emit a warning about "fmt" */
+ // ...
+ // }
+ //
+ // Another interaction that we need to support is 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 (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;
+ }
+ }
+ }
+ }
+ }
+ }
+ return SLCT_NotALiteral;
+}
+
+// Determine if an expression is a string literal or constant string.
+// If this function returns false on the arguments to a function expecting a
+// format string, we will usually need to emit a warning.
+// True string literals are then checked by CheckFormatString.
+static StringLiteralCheckType
+checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
+ Sema::FormatArgumentPassingKind APK, unsigned format_idx,
+ unsigned firstDataArg, Sema::FormatStringType Type,
+ Sema::VariadicCallType CallType, bool NoNote,
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset,
+ bool IgnoreStringsWithoutSpecifiers = false) {
+ auto T = checkFormatStringExprEvaluated(
+ S, E, Args, APK, format_idx, firstDataArg, Type, CallType, NoNote,
+ CheckedVarArgs, UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers);
+ if (T == SLCT_NotALiteral) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsRValue(Result, S.Context) && Result.Val.isLValue()) {
+ if (isa<CallExpr>(E) || isa<CXXMemberCallExpr>(E)) {
+ const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
+
+ if (LVE)
+ return checkFormatStringExprEvaluated(
+ S, LVE, Args, APK, format_idx, firstDataArg, Type, CallType,
+ /*NoNote*/ false, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
+ }
+
+ const auto *LVVD =
+ Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
+ if (isa_and_nonnull<const VarDecl>(LVVD))
+ return checkVarDecl(
+ S, E, Args, APK, format_idx, firstDataArg, Type, CallType, NoNote,
+ CheckedVarArgs, UncoveredArg, Offset, LVVD->getType(),
+ dyn_cast<const VarDecl>(LVVD), IgnoreStringsWithoutSpecifiers);
+ }
+ }
+ return T;
}
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
@@ -8976,7 +9057,7 @@
llvm::SmallBitVector CoveredArgs;
bool usesPositionalArgs = false;
bool atFirstArg = true;
- bool inFunctionCall;
+ bool NoNote;
Sema::VariadicCallType CallType;
llvm::SmallBitVector &CheckedVarArgs;
UncoveredArgHandler &UncoveredArg;
@@ -8988,14 +9069,14 @@
unsigned numDataArgs, const char *beg,
Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
- bool inFunctionCall, Sema::VariadicCallType callType,
+ bool NoNote, Sema::VariadicCallType callType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg),
- ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx),
- inFunctionCall(inFunctionCall), CallType(callType),
- CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
+ ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx), NoNote(NoNote),
+ CallType(callType), CheckedVarArgs(CheckedVarArgs),
+ UncoveredArg(UncoveredArg) {
CoveredArgs.resize(numDataArgs);
CoveredArgs.reset();
}
@@ -9031,7 +9112,7 @@
template <typename Range>
static void
- EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr,
+ EmitFormatDiagnostic(Sema &S, bool NoNote, const Expr *ArgumentExpr,
const PartialDiagnostic &PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
ArrayRef<FixItHint> Fixit = None);
@@ -9362,16 +9443,17 @@
bool IsStringLocation,
Range StringRange,
ArrayRef<FixItHint> FixIt) {
- EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
- Loc, IsStringLocation, StringRange, FixIt);
+ EmitFormatDiagnostic(S, NoNote, Args[FormatIdx], PDiag, Loc, IsStringLocation,
+ StringRange, FixIt);
}
/// If the format string is not within the function call, emit a note
/// so that the function call and string are in diagnostic messages.
///
-/// \param InFunctionCall if true, the format string is within the function
-/// call and only one diagnostic message will be produced. Otherwise, an
-/// extra note will be emitted pointing to location of the format string.
+/// \param NoNote if true, only one diagnostic message will be produced. Perhaps
+/// the format string is within the function call or is evaluted which does not
+/// have an appropriate source location. Otherwise, an extra note will be
+/// emitted pointing to location of the format string.
///
/// \param ArgumentExpr the expression that is passed as the format string
/// argument in the function call. Used for getting locations when two
@@ -9395,10 +9477,10 @@
/// \param FixIt optional fix it hint for the format string.
template <typename Range>
void CheckFormatHandler::EmitFormatDiagnostic(
- Sema &S, bool InFunctionCall, const Expr *ArgumentExpr,
+ Sema &S, bool NoNote, const Expr *ArgumentExpr,
const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation,
Range StringRange, ArrayRef<FixItHint> FixIt) {
- if (InFunctionCall) {
+ if (NoNote) {
const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag);
D << StringRange;
D << FixIt;
@@ -9427,13 +9509,12 @@
unsigned numDataArgs, bool isObjC, const char *beg,
Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
- bool inFunctionCall, Sema::VariadicCallType CallType,
+ bool NoNote, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
- numDataArgs, beg, APK, Args, formatIdx,
- inFunctionCall, CallType, CheckedVarArgs,
- UncoveredArg) {}
+ numDataArgs, beg, APK, Args, formatIdx, NoNote,
+ CallType, CheckedVarArgs, UncoveredArg) {}
bool isObjCContext() const { return FSType == Sema::FST_NSString; }
@@ -10375,13 +10456,12 @@
unsigned firstDataArg, unsigned numDataArgs,
const char *beg, Sema::FormatArgumentPassingKind APK,
ArrayRef<const Expr *> Args, unsigned formatIdx,
- bool inFunctionCall, Sema::VariadicCallType CallType,
+ bool NoNote, Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
- numDataArgs, beg, APK, Args, formatIdx,
- inFunctionCall, CallType, CheckedVarArgs,
- UncoveredArg) {}
+ numDataArgs, beg, APK, Args, formatIdx, NoNote,
+ CallType, CheckedVarArgs, UncoveredArg) {}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
@@ -10544,13 +10624,13 @@
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,
+ bool NoNote, 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(
- S, inFunctionCall, Args[format_idx],
+ S, NoNote, Args[format_idx],
S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getBeginLoc(),
/*IsStringLocation*/ true, OrigFormatExpr->getSourceRange());
return;
@@ -10576,7 +10656,7 @@
// embedded null character.
if (TypeSize <= StrRef.size() && !StrRef.substr(0, TypeSize).contains('\0')) {
CheckFormatHandler::EmitFormatDiagnostic(
- S, inFunctionCall, Args[format_idx],
+ S, NoNote, Args[format_idx],
S.PDiag(diag::warn_printf_format_string_not_null_terminated),
FExpr->getBeginLoc(),
/*IsStringLocation=*/true, OrigFormatExpr->getSourceRange());
@@ -10586,8 +10666,8 @@
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
CheckFormatHandler::EmitFormatDiagnostic(
- S, inFunctionCall, Args[format_idx],
- S.PDiag(diag::warn_empty_format_string), FExpr->getBeginLoc(),
+ S, NoNote, Args[format_idx], S.PDiag(diag::warn_empty_format_string),
+ FExpr->getBeginLoc(),
/*IsStringLocation*/ true, OrigFormatExpr->getSourceRange());
return;
}
@@ -10598,8 +10678,7 @@
CheckPrintfHandler H(
S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs,
(Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, APK,
- Args, format_idx, inFunctionCall, CallType, CheckedVarArgs,
- UncoveredArg);
+ Args, format_idx, NoNote, CallType, CheckedVarArgs, UncoveredArg);
if (!analyze_format_string::ParsePrintfString(
H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(),
@@ -10607,7 +10686,7 @@
H.DoneProcessing();
} else if (Type == Sema::FST_Scanf) {
CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
- numDataArgs, Str, APK, Args, format_idx, inFunctionCall,
+ numDataArgs, Str, APK, Args, format_idx, NoNote,
CallType, CheckedVarArgs, UncoveredArg);
if (!analyze_format_string::ParseScanfString(
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits