Make sure we perform the variadic method check correctly for calls to a member operat...
authorEli Friedman <eli.friedman@gmail.com>
Thu, 11 Oct 2012 00:30:58 +0000 (00:30 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Thu, 11 Oct 2012 00:30:58 +0000 (00:30 +0000)
llvm-svn: 165678

clang/lib/Sema/SemaChecking.cpp
clang/test/SemaCXX/attr-format.cpp
clang/test/SemaCXX/vararg-non-pod.cpp

index 81be8bf..63c7bdd 100644 (file)
@@ -542,11 +542,23 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
 /// and safety properties not strictly enforced by the C type system.
 bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
                              const FunctionProtoType *Proto) {
-  bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall);
+  bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) &&
+                              isa<CXXMethodDecl>(FDecl);
+  bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) ||
+                          IsMemberOperatorCall;
   VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
                                                   TheCall->getCallee());
   unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
-  checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs,
+  Expr** Args = TheCall->getArgs();
+  unsigned NumArgs = TheCall->getNumArgs();
+  if (isa<CXXOperatorCallExpr>(TheCall) && isa<CXXMethodDecl>(FDecl)) {
+    // If this is a call to a member operator, hide the first argument
+    // from checkCall.
+    // FIXME: Our choice of AST representation here is less than ideal.
+    ++Args;
+    --NumArgs;
+  }
+  checkCall(FDecl, Args, NumArgs, NumProtoArgs,
             IsMemberFunction, TheCall->getRParenLoc(),
             TheCall->getCallee()->getSourceRange(), CallType);
 
index da134a1..3d5c339 100644 (file)
@@ -14,6 +14,8 @@ struct S {
       expected-error{{out of bounds}}
   const char* h3(const char*) __attribute__((format_arg(1))); // \
       expected-error{{invalid for the implicit this argument}}
+
+  void operator() (const char*, ...) __attribute__((format(printf, 2, 3)));
 };
 
 // PR5521
@@ -33,3 +35,9 @@ namespace PR8625 {
     s.f(str, "%s", str);
   }
 }
+
+// Make sure we interpret member operator calls as having an implicit
+// this argument.
+void test_operator_call(S s, const char* str) {
+  s("%s", str);
+}
index 86b560e..da06d95 100644 (file)
@@ -123,3 +123,21 @@ int t9(int n) {
   // Make sure the error works in potentially-evaluated sizeof
   return (int)sizeof(*(Helper(Foo()), (int (*)[n])0)); // expected-warning{{cannot pass object of non-POD type}}
 }
+
+// PR14057
+namespace t10 {
+  struct F {
+    F();
+  };
+
+  struct S {
+    void operator()(F, ...);
+  };
+
+  void foo() {
+    S s;
+    F f;
+    s.operator()(f);
+    s(f);
+  }
+}