Submitted by:
Reviewed by:
Refine Sema::ParseCallExpr() diags (range support, add types).

Before:

func-assign.c:27:11: warning: passing argument 1 from incompatible pointer type
  pintFunc(&FOO);
          ^
func-assign.c:28:12: error: incompatible type for argument 1
  floatFunc(&FOO);
           ^
func-assign.c:29:12: error: too many arguments to function
  floatFunc(1,2,3);
           ^
After:

func-assign.c:27:11: warning: passing incompatible pointer 'struct foo *' to function expecting 'int *'
  pintFunc(&FOO);
  ~~~~~~~~^~~~~
func-assign.c:28:12: error: passing incompatible type 'struct foo *' to function expecting 'float'
  floatFunc(&FOO);
  ~~~~~~~~~^~~~~
func-assign.c:29:12: error: too many arguments to function
  floatFunc(1,2,3);
  ~~~~~~~~~^  ~

llvm-svn: 39513
This commit is contained in:
Steve Naroff
2007-05-28 19:25:56 +00:00
parent 758ada12f4
commit 8563f65042
3 changed files with 58 additions and 17 deletions

View File

@@ -363,7 +363,11 @@ Action::ExprResult Sema::
ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
ExprTy **Args, unsigned NumArgsInCall,
SourceLocation *CommaLocs, SourceLocation RParenLoc) {
QualType qType = ((Expr *)Fn)->getType();
Expr *funcExpr = (Expr *)Fn;
assert(funcExpr && "no function call expression");
QualType qType = funcExpr->getType();
assert(!qType.isNull() && "no type for function call expression");
@@ -382,16 +386,24 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
unsigned NumArgsToCheck = NumArgsInCall;
if (NumArgsInCall < NumArgsInProto)
Diag(LParenLoc, diag::err_typecheck_call_too_few_args);
Diag(LParenLoc, diag::err_typecheck_call_too_few_args,
funcExpr->getSourceRange());
else if (NumArgsInCall > NumArgsInProto) {
if (!proto->isVariadic())
Diag(LParenLoc, diag::err_typecheck_call_too_many_args);
if (!proto->isVariadic()) {
Diag(LParenLoc, diag::err_typecheck_call_too_many_args,
funcExpr->getSourceRange(),
((Expr **)Args)[NumArgsInProto]->getSourceRange());
}
NumArgsToCheck = NumArgsInProto;
}
// Continue to check argument types (even if we have too few/many args).
for (unsigned i = 0; i < NumArgsToCheck; i++) {
Expr *argExpr = ((Expr **)Args)[i];
assert(argExpr && "ParseCallExpr(): missing argument expression");
QualType lhsType = proto->getArgType(i);
QualType rhsType = ((Expr **)Args)[i]->getType();
QualType rhsType = argExpr->getType();
if (lhsType == rhsType) // common case, fast path...
continue;
@@ -401,28 +413,34 @@ ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
SourceLocation l = (i == 0) ? LParenLoc : CommaLocs[i-1];
// decode the result (notice that AST's are still created for extensions).
// FIXME: consider fancier error diagnostics (since this is quite common).
// #1: emit the actual prototype arg...requires adding source loc info.
// #2: pass Diag the offending argument type...requires hacking Diag.
// FIXME: decide to include/exclude the argument # (decided to remove
// it for the incompatible diags below). The range should be sufficient.
switch (result) {
case Compatible:
break;
case PointerFromInt:
// check for null pointer constant (C99 6.3.2.3p3)
if (!((Expr **)Args)[i]->isNullPointerConstant())
Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1));
if (!argExpr->isNullPointerConstant())
Diag(l, diag::ext_typecheck_passing_pointer_from_int, utostr(i+1),
funcExpr->getSourceRange(), argExpr->getSourceRange());
break;
case IntFromPointer:
Diag(l, diag::ext_typecheck_passing_int_from_pointer, utostr(i+1));
Diag(l, diag::ext_typecheck_passing_int_from_pointer, utostr(i+1),
funcExpr->getSourceRange(), argExpr->getSourceRange());
break;
case IncompatiblePointer:
Diag(l, diag::ext_typecheck_passing_incompatible_pointer, utostr(i+1));
Diag(l, diag::ext_typecheck_passing_incompatible_pointer,
rhsType.getAsString(), lhsType.getAsString(),
funcExpr->getSourceRange(), argExpr->getSourceRange());
break;
case CompatiblePointerDiscardsQualifiers:
Diag(l, diag::ext_typecheck_passing_discards_qualifiers, utostr(i+1));
Diag(l, diag::ext_typecheck_passing_discards_qualifiers, utostr(i+1),
funcExpr->getSourceRange(), argExpr->getSourceRange());
break;
case Incompatible:
return Diag(l, diag::err_typecheck_passing_incompatible, utostr(i+1));
return Diag(l, diag::err_typecheck_passing_incompatible,
rhsType.getAsString(), lhsType.getAsString(),
funcExpr->getSourceRange(), argExpr->getSourceRange());
}
}
// Even if the types checked, bail if we had the wrong number of arguments.

View File

@@ -103,6 +103,23 @@
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXBuildStyle section */
84FADE170C0B37FF00330902 /* Development */ = {
isa = PBXBuildStyle;
buildSettings = {
COPY_PHASE_STRIP = NO;
};
name = Development;
};
84FADE180C0B37FF00330902 /* Deployment */ = {
isa = PBXBuildStyle;
buildSettings = {
COPY_PHASE_STRIP = YES;
};
name = Deployment;
};
/* End PBXBuildStyle section */
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
@@ -538,6 +555,12 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
buildSettings = {
};
buildStyles = (
84FADE170C0B37FF00330902 /* Development */,
84FADE180C0B37FF00330902 /* Deployment */,
);
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";

View File

@@ -585,13 +585,13 @@ DIAG(err_typecheck_call_too_few_args, ERROR,
DIAG(err_typecheck_call_too_many_args, ERROR,
"too many arguments to function")
DIAG(err_typecheck_passing_incompatible, ERROR,
"incompatible type for argument %0")
"passing incompatible type '%0' to function expecting '%1'")
DIAG(ext_typecheck_passing_incompatible_pointer, EXTENSION,
"passing incompatible pointer '%0' to function expecting '%1'")
DIAG(ext_typecheck_passing_int_from_pointer, EXTENSION,
"passing argument %0 makes integer from pointer without a cast")
DIAG(ext_typecheck_passing_pointer_from_int, EXTENSION,
"passing argument %0 makes pointer from integer without a cast")
DIAG(ext_typecheck_passing_incompatible_pointer, EXTENSION,
"passing argument %0 from incompatible pointer type")
DIAG(ext_typecheck_passing_discards_qualifiers, EXTENSION,
"passing argument %0 discards qualifiers from pointer target type")
DIAG(err_typecheck_return_incompatible, ERROR,