r336239 - [Sema] Consider all format_arg attributes.

Michael Kruse via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 3 18:37:11 PDT 2018


Author: meinersbur
Date: Tue Jul  3 18:37:11 2018
New Revision: 336239

URL: http://llvm.org/viewvc/llvm-project?rev=336239&view=rev
Log:
[Sema] Consider all format_arg attributes.

If a function has multiple format_arg attributes, clang only considers
the first it finds (because AttributeLists are in reverse order, not
necessarily the textually first) and ignores all others.

Loop over all FormatArgAttr to print warnings for all declared
format_arg attributes.

For instance, libintl's ngettext (select plural or singular version of
format string) has two __format_arg__ attributes.

Differential Revision: https://reviews.llvm.org/D48734

Modified:
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/Sema/attr-format_arg.c

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=336239&r1=336238&r2=336239&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Jul  3 18:37:11 2018
@@ -5518,13 +5518,22 @@ checkFormatStringExpr(Sema &S, const Exp
   case Stmt::CXXMemberCallExprClass: {
     const CallExpr *CE = cast<CallExpr>(E);
     if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
-      if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
+      bool IsFirst = true;
+      StringLiteralCheckType CommonResult;
+      for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
         const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-        return checkFormatStringExpr(S, Arg, Args,
-                                     HasVAListArg, format_idx, firstDataArg,
-                                     Type, CallType, InFunctionCall,
-                                     CheckedVarArgs, UncoveredArg, Offset);
-      } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+        StringLiteralCheckType Result = checkFormatStringExpr(
+            S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
+            CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+        if (IsFirst) {
+          CommonResult = Result;
+          IsFirst = false;
+        }
+      }
+      if (!IsFirst)
+        return CommonResult;
+
+      if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
         unsigned BuiltinID = FD->getBuiltinID();
         if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
             BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {

Modified: cfe/trunk/test/Sema/attr-format_arg.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-format_arg.c?rev=336239&r1=336238&r2=336239&view=diff
==============================================================================
--- cfe/trunk/test/Sema/attr-format_arg.c (original)
+++ cfe/trunk/test/Sema/attr-format_arg.c Tue Jul  3 18:37:11 2018
@@ -4,10 +4,27 @@ int printf(const char *, ...);
 
 const char* f(const char *s) __attribute__((format_arg(1)));
 
+const char *h(const char *msg1, const char *msg2)
+    __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
 void g(const char *s) {
   printf("%d", 123);
   printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}}
 
   printf(f("%d"), 123);
   printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}}
+
+  printf(h(
+    "", // expected-warning {{format string is empty}}
+    ""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+    "%d",
+    ""  // expected-warning {{format string is empty}}
+  ), 123);
+  printf(h(
+    "", // expected-warning {{format string is empty}}
+    "%d"
+  ), 123);
+  printf(h("%d", "%d"), 123);
 }




More information about the cfe-commits mailing list