move void argument checking from the parser to the semantic analysis stage.

This allows us to handle typedefs of void correctly.  This implements
clang/test/Sema/void_arg.c

llvm-svn: 39236
This commit is contained in:
Chris Lattner 2006-12-03 02:43:54 +00:00
parent d2e97c1f80
commit c81f079d7e
6 changed files with 89 additions and 28 deletions

View File

@ -137,12 +137,36 @@ TypeRef Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
// Otherwise, we have a function with an argument list that is
// potentially variadic.
SmallVector<TypeRef, 16> ArgTys;
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
if (FTI.ArgInfo[i].TypeInfo == 0)
TypeRef ArgTy = TypeRef::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo);
if (ArgTy.isNull())
return TypeRef(); // Error occurred parsing argument type.
ArgTys.push_back(TypeRef::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo));
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10). We record
// int(void) as a FunctionTypeProto with an empty argument list.
if (ArgTy->isVoidType()) {
// If this is something like 'float(int, void)', reject it.
if (FTI.NumArgs != 1 || FTI.isVariadic) {
Diag(DeclType.Loc, diag::err_void_only_param);
return TypeRef();
}
// Reject 'int(void abc)'.
if (FTI.ArgInfo[i].Ident) {
Diag(FTI.ArgInfo[i].IdentLoc,
diag::err_void_param_with_identifier);
return TypeRef();
}
// Do not add 'void' to the ArgTys list.
break;
}
ArgTys.push_back(ArgTy);
}
T = Context.getFunctionType(T, &ArgTys[0], FTI.NumArgs, FTI.isVariadic);
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
FTI.isVariadic);
}
break;
}

View File

@ -20,6 +20,14 @@ using namespace clang;
Type::~Type() {}
/// isVoidType - Helper method to determine if this is the 'void' type.
bool Type::isVoidType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(getCanonicalType())) {
// FIXME: USE ENUMS!
return !strcmp(BT->getName(), "void");
}
return false;
}
//===----------------------------------------------------------------------===//
// Type Printing

View File

@ -1020,28 +1020,6 @@ void Parser::ParseParenDeclarator(Declarator &D) {
DS.ClearStorageClassSpecs();
}
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10).
if (ParmDecl.getNumTypeObjects() == 0 && // not void*.
DS.getTypeSpecType() == DeclSpec::TST_void) {
if (ParmDecl.getIdentifier()) {
Diag(ParmDecl.getIdentifierLoc(),
diag::err_void_param_with_identifier);
ErrorEmitted = true;
}
if (!ErrorEmitted &&
(!ParamInfo.empty() || Tok.getKind() != tok::r_paren)) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_void_only_param);
ErrorEmitted = true;
}
// We know now that we either emitted an error or that the next token
// is a ')'. Exit this loop with an empty ParamInfo list, instead of
// adding void explicitly to the list.
break;
}
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
Action::TypeResult ParamTy =

View File

@ -137,12 +137,36 @@ TypeRef Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
// Otherwise, we have a function with an argument list that is
// potentially variadic.
SmallVector<TypeRef, 16> ArgTys;
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
if (FTI.ArgInfo[i].TypeInfo == 0)
TypeRef ArgTy = TypeRef::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo);
if (ArgTy.isNull())
return TypeRef(); // Error occurred parsing argument type.
ArgTys.push_back(TypeRef::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo));
// Look for 'void'. void is allowed only as a single argument to a
// function with no other parameters (C99 6.7.5.3p10). We record
// int(void) as a FunctionTypeProto with an empty argument list.
if (ArgTy->isVoidType()) {
// If this is something like 'float(int, void)', reject it.
if (FTI.NumArgs != 1 || FTI.isVariadic) {
Diag(DeclType.Loc, diag::err_void_only_param);
return TypeRef();
}
// Reject 'int(void abc)'.
if (FTI.ArgInfo[i].Ident) {
Diag(FTI.ArgInfo[i].IdentLoc,
diag::err_void_param_with_identifier);
return TypeRef();
}
// Do not add 'void' to the ArgTys list.
break;
}
ArgTys.push_back(ArgTy);
}
T = Context.getFunctionType(T, &ArgTys[0], FTI.NumArgs, FTI.isVariadic);
T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
FTI.isVariadic);
}
break;
}

View File

@ -167,6 +167,10 @@ public:
bool isCanonical() const { return CanonicalType == this; }
Type *getCanonicalType() const { return CanonicalType; }
/// isVoidType - Helper method to determine if this is the 'void' type.
bool isVoidType() const;
virtual void getAsString(std::string &InnerString) const = 0;
static bool classof(const Type *) { return true; }
@ -179,6 +183,8 @@ class BuiltinType : public Type {
public:
BuiltinType(const char *name) : Type(Builtin, 0), Name(name) {}
const char *getName() const { return Name; }
virtual void getAsString(std::string &InnerString) const;
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }

View File

@ -0,0 +1,21 @@
/* RUN: clang -parse-ast %s 2>&1 | grep '6 diagnostics'
*/
typedef void Void;
void foo() {
int X;
X = sizeof(int (void a));
X = sizeof(int (int, void));
X = sizeof(int (void, ...));
X = sizeof(int (Void a));
X = sizeof(int (int, Void));
X = sizeof(int (Void, ...));
// Accept these.
X = sizeof(int (void));
X = sizeof(int (Void));
}