[cfe-commits] r43050 - in /cfe/trunk: Sema/Sema.h Sema/SemaExpr.cpp include/clang/Basic/DiagnosticKinds.def test/Sema/argument-checking.m

Steve Naroff snaroff at apple.com
Tue Oct 16 16:12:48 PDT 2007


Author: snaroff
Date: Tue Oct 16 18:12:48 2007
New Revision: 43050

URL: http://llvm.org/viewvc/llvm-project?rev=43050&view=rev
Log:

Add Sema::CheckMessageArgumentTypes()...


Added:
    cfe/trunk/test/Sema/argument-checking.m
Modified:
    cfe/trunk/Sema/Sema.h
    cfe/trunk/Sema/SemaExpr.cpp
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def

Modified: cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Sema/Sema.h?rev=43050&r1=43049&r2=43050&view=diff

==============================================================================
--- cfe/trunk/Sema/Sema.h (original)
+++ cfe/trunk/Sema/Sema.h Tue Oct 16 18:12:48 2007
@@ -511,7 +511,7 @@
     // from the Sel.getNumArgs().
     TypeTy **ArgTypes, IdentifierInfo **ArgNames,
     AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind);
-                    
+
   // ActOnClassMessage - used for both unary and keyword messages.
   // ArgExprs is optional - if it is present, the number of expressions
   // is obtained from Sel.getNumArgs().
@@ -631,7 +631,11 @@
   void CheckConstantInitList(QualType DeclType, InitListExpr *IList, 
                              QualType ElementType, bool isStatic, 
                              int &nInitializers, bool &hadError);
-   
+                             
+  // returns true if there were any incompatible arguments.                           
+  bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+                                 ObjcMethodDecl *Method);
+                    
   /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
   /// the specified width and sign.  If an overflow occurs, detect it and emit
   /// the specified diagnostic.

Modified: cfe/trunk/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Sema/SemaExpr.cpp?rev=43050&r1=43049&r2=43050&view=diff

==============================================================================
--- cfe/trunk/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/Sema/SemaExpr.cpp Tue Oct 16 18:12:48 2007
@@ -1928,6 +1928,67 @@
   return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc);
 }
 
+
+bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+                                     ObjcMethodDecl *Method) {
+  bool anyIncompatibleArgs = false;
+  
+  for (unsigned i = 0; i < NumArgs; i++) {
+    Expr *argExpr = Args[i];
+    assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+    
+    QualType lhsType = Method->getParamDecl(i)->getType();
+    QualType rhsType = argExpr->getType();
+
+    // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. 
+    if (const ArrayType *ary = lhsType->getAsArrayType())
+      lhsType = Context.getPointerType(ary->getElementType());
+    else if (lhsType->isFunctionType())
+      lhsType = Context.getPointerType(lhsType);
+
+    AssignmentCheckResult result = CheckSingleAssignmentConstraints(lhsType,
+                                                                    argExpr);
+    if (Args[i] != argExpr) // The expression was converted.
+      Args[i] = argExpr; // Make sure we store the converted expression.
+    SourceLocation l = argExpr->getLocStart();
+
+    // decode the result (notice that AST's are still created for extensions).
+    switch (result) {
+    case Compatible:
+      break;
+    case PointerFromInt:
+      // check for null pointer constant (C99 6.3.2.3p3)
+      if (!argExpr->isNullPointerConstant(Context)) {
+        Diag(l, diag::ext_typecheck_sending_pointer_int, 
+             lhsType.getAsString(), rhsType.getAsString(),
+             argExpr->getSourceRange());
+      }
+      break;
+    case IntFromPointer:
+      Diag(l, diag::ext_typecheck_sending_pointer_int, 
+           lhsType.getAsString(), rhsType.getAsString(),
+           argExpr->getSourceRange());
+      break;
+    case IncompatiblePointer:
+      Diag(l, diag::ext_typecheck_sending_incompatible_pointer, 
+           rhsType.getAsString(), lhsType.getAsString(),
+           argExpr->getSourceRange());
+      break;
+    case CompatiblePointerDiscardsQualifiers:
+      Diag(l, diag::ext_typecheck_passing_discards_qualifiers,
+           rhsType.getAsString(), lhsType.getAsString(),
+           argExpr->getSourceRange());
+      break;
+    case Incompatible:
+      Diag(l, diag::err_typecheck_sending_incompatible,
+           rhsType.getAsString(), lhsType.getAsString(),
+           argExpr->getSourceRange());
+      anyIncompatibleArgs = true;
+    }
+  }
+  return anyIncompatibleArgs;
+}
+
 // ActOnClassMessage - used for both unary and keyword messages.
 // ArgExprs is optional - if it is present, the number of expressions
 // is obtained from Sel.getNumArgs().
@@ -1937,6 +1998,7 @@
 {
   assert(receiverName && "missing receiver class name");
 
+  Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
   ObjcInterfaceDecl* ClassDecl = getObjCInterfaceDecl(receiverName);
   ObjcMethodDecl *Method = ClassDecl->lookupClassMethod(Sel);
   QualType returnType;
@@ -1946,9 +2008,11 @@
     returnType = GetObjcIdType();
   } else {
     returnType = Method->getResultType();
+    if (Sel.getNumArgs()) {
+      if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+        return true;
+    }
   }
-  // Expr *RExpr = global reference to the class symbol...
-  Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
   return new ObjCMessageExpr(receiverName, Sel, returnType, lbrac, rbrac,
                              ArgExprs);
 }
@@ -1962,6 +2026,7 @@
 {
   assert(receiver && "missing receiver expression");
   
+  Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
   Expr *RExpr = static_cast<Expr *>(receiver);
   QualType receiverType = RExpr->getType();
   QualType returnType;
@@ -1974,6 +2039,9 @@
       returnType = GetObjcIdType();
     } else {
       returnType = Method->getResultType();
+      if (Sel.getNumArgs())
+        if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+          return true;
     }
   } else {
     // FIXME (snaroff): checking in this code from Patrick. Needs to be
@@ -1997,8 +2065,10 @@
       returnType = GetObjcIdType();
     } else {
       returnType = Method->getResultType();
+      if (Sel.getNumArgs())
+        if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+          return true;
     }
   }
-  Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
   return new ObjCMessageExpr(RExpr, Sel, returnType, lbrac, rbrac, ArgExprs);
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=43050&r1=43049&r2=43050&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Oct 16 18:12:48 2007
@@ -763,6 +763,12 @@
      "incompatible types passing '%1' to function expecting '%0'")
 DIAG(ext_typecheck_passing_discards_qualifiers, WARNING,
      "passing '%0' to '%1' discards qualifiers")
+DIAG(err_typecheck_sending_incompatible, ERROR,
+     "incompatible types passing '%0' to method expecting '%1'")
+DIAG(ext_typecheck_sending_incompatible_pointer, WARNING,
+     "incompatible pointer types passing '%0' to method expecting '%1'")
+DIAG(ext_typecheck_sending_pointer_int, WARNING,
+     "incompatible types passing '%1' to method expecting '%0'")
 DIAG(err_typecheck_cond_expect_scalar, ERROR,
      "used type '%0' where arithmetic or pointer type is required")
 DIAG(err_typecheck_expect_scalar_operand, ERROR,

Added: cfe/trunk/test/Sema/argument-checking.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/argument-checking.m?rev=43050&view=auto

==============================================================================
--- cfe/trunk/test/Sema/argument-checking.m (added)
+++ cfe/trunk/test/Sema/argument-checking.m Tue Oct 16 18:12:48 2007
@@ -0,0 +1,27 @@
+// RUN: clang -fsyntax-only -verify %s
+
+typedef struct objc_object *id;
+
+struct S { int a; };
+
+extern int charStarFunc(char *);
+extern int charFunc(char);
+
+ at interface Test
++alloc;
+-(int)charStarMeth:(char *)s;
+-structMeth:(struct S)s;
+-structMeth:(struct S)s :(struct S)s2;
+ at end
+
+void test() {
+  id obj = [Test alloc];
+  struct S sInst;
+
+  charStarFunc(1); // expected-warning {{incompatible types passing 'int' to function expecting 'char *'}}
+  charFunc("abc"); // expected-warning {{incompatible types passing 'char *' to function expecting 'char'}}
+
+  [obj charStarMeth:1]; // expected-warning {{incompatible types passing 'int' to method expecting 'char *'}}
+  [obj structMeth:1]; // expected-error {{incompatible types passing 'int' to method expecting 'struct S'}}
+  [obj structMeth:sInst :1]; // expected-error {{incompatible types passing 'int' to method expecting 'struct S'}}
+}





More information about the cfe-commits mailing list