forked from OSchip/llvm-project
parent
7bcc28bf6c
commit
077c83bddb
|
|
@ -511,7 +511,7 @@ public:
|
|||
// 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 @@ private:
|
|||
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.
|
||||
|
|
|
|||
|
|
@ -1928,6 +1928,67 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
|
|||
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 @@ Sema::ExprResult Sema::ActOnClassMessage(
|
|||
{
|
||||
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 @@ Sema::ExprResult Sema::ActOnClassMessage(
|
|||
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 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
|
|||
{
|
||||
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 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
|
|||
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 @@ Sema::ExprResult Sema::ActOnInstanceMessage(
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -763,6 +763,12 @@ DIAG(ext_typecheck_passing_pointer_int, WARNING,
|
|||
"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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
@interface Test
|
||||
+alloc;
|
||||
-(int)charStarMeth:(char *)s;
|
||||
-structMeth:(struct S)s;
|
||||
-structMeth:(struct S)s :(struct S)s2;
|
||||
@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'}}
|
||||
}
|
||||
Loading…
Reference in New Issue