[cfe-commits] r39232 - in /cfe/cfe/trunk: AST/ASTContext.cpp AST/SemaType.cpp AST/Type.cpp Parse/ParseDecl.cpp Sema/SemaType.cpp include/clang/AST/ASTContext.h include/clang/AST/Type.h
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:41:38 PDT 2007
Author: sabre
Date: Wed Jul 11 11:41:38 2007
New Revision: 39232
URL: http://llvm.org/viewvc/llvm-project?rev=39232&view=rev
Log:
implement AST representation for function types with and without a prototype.
This lets us pretty print stuff like this:
void foo() {
int X;
X = sizeof(void (*(*)())());
X = sizeof(int(*)(int, float, ...));
X = sizeof(void (*(int arga, void (*argb)(double Y)))(void* Z));
as:
X = sizeof(void (*(*)())())
X = sizeof(int (*)(int, float, ...))
X = sizeof(void (*(int, void (*)(double)))(void *))
Ah the wonders of 'modern' C syntax!
Modified:
cfe/cfe/trunk/AST/ASTContext.cpp
cfe/cfe/trunk/AST/SemaType.cpp
cfe/cfe/trunk/AST/Type.cpp
cfe/cfe/trunk/Parse/ParseDecl.cpp
cfe/cfe/trunk/Sema/SemaType.cpp
cfe/cfe/trunk/include/clang/AST/ASTContext.h
cfe/cfe/trunk/include/clang/AST/Type.h
Modified: cfe/cfe/trunk/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/ASTContext.cpp?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/ASTContext.cpp (original)
+++ cfe/cfe/trunk/AST/ASTContext.cpp Wed Jul 11 11:41:38 2007
@@ -14,6 +14,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallVector.h"
using namespace llvm;
using namespace clang;
@@ -25,7 +26,13 @@
ASTContext::~ASTContext() {
// Deallocate all the types.
while (!Types.empty()) {
- delete Types.back();
+ if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(Types.back())) {
+ // Destroy the object, but don't call delete. These are malloc'd.
+ FT->~FunctionTypeProto();
+ free(FT);
+ } else {
+ delete Types.back();
+ }
Types.pop_back();
}
}
@@ -118,6 +125,79 @@
return Types.back();
}
+/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
+///
+TypeRef ASTContext::getFunctionTypeNoProto(TypeRef ResultTy) {
+ // FIXME: This is obviously braindead!
+ // Unique functions, to guarantee there is only one function of a particular
+ // structure.
+ for (unsigned i = 0, e = Types.size(); i != e; ++i)
+ if (FunctionTypeNoProto *FTy = dyn_cast<FunctionTypeNoProto>(Types[i]))
+ if (FTy->getResultType() == ResultTy)
+ return Types[i];
+
+ Type *Canonical = 0;
+ if (!ResultTy->isCanonical())
+ Canonical =getFunctionTypeNoProto(ResultTy.getCanonicalType()).getTypePtr();
+
+ Types.push_back(new FunctionTypeNoProto(ResultTy, Canonical));
+ return Types.back();
+}
+
+/// getFunctionType - Return a normal function type with a typed argument
+/// list. isVariadic indicates whether the argument list includes '...'.
+TypeRef ASTContext::getFunctionType(TypeRef ResultTy, TypeRef *ArgArray,
+ unsigned NumArgs, bool isVariadic) {
+ // FIXME: This is obviously braindead!
+ // Unique functions, to guarantee there is only one function of a particular
+ // structure.
+ for (unsigned i = 0, e = Types.size(); i != e; ++i) {
+ if (FunctionTypeProto *FTy = dyn_cast<FunctionTypeProto>(Types[i]))
+ if (FTy->getResultType() == ResultTy &&
+ FTy->getNumArgs() == NumArgs &&
+ FTy->isVariadic() == isVariadic) {
+ bool Match = true;
+ for (unsigned arg = 0; arg != NumArgs; ++arg) {
+ if (FTy->getArgType(arg) != ArgArray[arg]) {
+ Match = false;
+ break;
+ }
+ }
+ if (Match)
+ return Types[i];
+ }
+ }
+
+ // Determine whether the type being created is already canonical or not.
+ bool isCanonical = ResultTy->isCanonical();
+ for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
+ if (!ArgArray[i]->isCanonical())
+ isCanonical = false;
+
+ // If this type isn't canonical, get the canonical version of it.
+ Type *Canonical = 0;
+ if (!isCanonical) {
+ SmallVector<TypeRef, 16> CanonicalArgs;
+ CanonicalArgs.reserve(NumArgs);
+ for (unsigned i = 0; i != NumArgs; ++i)
+ CanonicalArgs.push_back(ArgArray[i].getCanonicalType());
+
+ Canonical = getFunctionType(ResultTy.getCanonicalType(),
+ &CanonicalArgs[0], NumArgs,
+ isVariadic).getTypePtr();
+ }
+
+ // FunctionTypeProto objects are not allocated with new because they have a
+ // variable size array (for parameter types) at the end of them.
+ FunctionTypeProto *FTP =
+ (FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) +
+ (NumArgs-1)*sizeof(TypeRef));
+ new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic,
+ Canonical);
+
+ Types.push_back(FTP);
+ return FTP;
+}
/// getTypeDeclType - Return the unique reference to the type for the
/// specified typename decl.
Modified: cfe/cfe/trunk/AST/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaType.cpp?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/SemaType.cpp (original)
+++ cfe/cfe/trunk/AST/SemaType.cpp Wed Jul 11 11:41:38 2007
@@ -126,7 +126,25 @@
break;
}
case DeclaratorChunk::Function:
- return TypeRef(); // FIXME: implement these!
+ // If the function declarator has a prototype (i.e. it is not () and
+ // does not have a K&R-style identifier list), then the arguments are part
+ // of the type, otherwise the argument list is ().
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ if (!FTI.hasPrototype) {
+ // Simple void foo(), where the incoming T is the result type.
+ T = Context.getFunctionTypeNoProto(T);
+ } else {
+ // 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)
+ return TypeRef(); // Error occurred parsing argument type.
+ ArgTys.push_back(TypeRef::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo));
+ }
+ T = Context.getFunctionType(T, &ArgTys[0], FTI.NumArgs, FTI.isVariadic);
+ }
+ break;
}
}
Modified: cfe/cfe/trunk/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Type.cpp?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:41:38 2007
@@ -97,6 +97,41 @@
ElementType.getAsString(S);
}
+
+void FunctionTypeNoProto::getAsString(std::string &S) const {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "()";
+ getResultType().getAsString(S);
+}
+
+void FunctionTypeProto::getAsString(std::string &S) const {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "(";
+ std::string Tmp;
+ for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
+ if (i) S += ", ";
+ getArgType(i).getAsString(Tmp);
+ S += Tmp;
+ Tmp.clear();
+ }
+
+ if (isVariadic()) {
+ if (getNumArgs())
+ S += ", ";
+ S += "...";
+ }
+
+ S += ")";
+ getResultType().getAsString(S);
+}
+
+
void TypeNameType::getAsString(std::string &InnerString) const {
if (InnerString.empty()) {
InnerString = getDecl()->getIdentifier()->getName();
Modified: cfe/cfe/trunk/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseDecl.cpp?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/ParseDecl.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseDecl.cpp Wed Jul 11 11:41:38 2007
@@ -1020,6 +1020,11 @@
DS.ClearStorageClassSpecs();
}
+
+ // FIXME: If this is 'void', validate it's ok, then break out of the loop
+ // it must be 'int foo(void)'. Break from loop to prevent trouble with
+ // things like 'int foo(void, ...)' or 'int foo(void, int)'.
+
// Inform the actions module about the parameter declarator, so it gets
// added to the current scope.
Action::TypeResult ParamTy =
Modified: cfe/cfe/trunk/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaType.cpp?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/Sema/SemaType.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaType.cpp Wed Jul 11 11:41:38 2007
@@ -126,7 +126,25 @@
break;
}
case DeclaratorChunk::Function:
- return TypeRef(); // FIXME: implement these!
+ // If the function declarator has a prototype (i.e. it is not () and
+ // does not have a K&R-style identifier list), then the arguments are part
+ // of the type, otherwise the argument list is ().
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ if (!FTI.hasPrototype) {
+ // Simple void foo(), where the incoming T is the result type.
+ T = Context.getFunctionTypeNoProto(T);
+ } else {
+ // 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)
+ return TypeRef(); // Error occurred parsing argument type.
+ ArgTys.push_back(TypeRef::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo));
+ }
+ T = Context.getFunctionType(T, &ArgTys[0], FTI.NumArgs, FTI.isVariadic);
+ }
+ break;
}
}
Modified: cfe/cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/ASTContext.h?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/cfe/trunk/include/clang/AST/ASTContext.h Wed Jul 11 11:41:38 2007
@@ -54,6 +54,15 @@
TypeRef getArrayType(TypeRef EltTy, ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals, void *NumElts);
+ /// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'.
+ ///
+ TypeRef getFunctionTypeNoProto(TypeRef ResultTy);
+
+ /// getFunctionType - Return a normal function type with a typed argument
+ /// list. isVariadic indicates whether the argument list includes '...'.
+ TypeRef getFunctionType(TypeRef ResultTy, TypeRef *ArgArray,
+ unsigned NumArgs, bool isVariadic);
+
/// getTypeDeclType - Return the unique reference to the type for the
/// specified typename decl.
TypeRef getTypeDeclType(TypeDecl *Decl);
Modified: cfe/cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Type.h?rev=39232&r1=39231&r2=39232&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:41:38 2007
@@ -148,7 +148,7 @@
class Type {
public:
enum TypeClass {
- Builtin, Pointer, Array, TypeName
+ Builtin, Pointer, Array, FunctionNoProto, FunctionProto, TypeName
};
private:
Type *CanonicalType;
@@ -185,7 +185,7 @@
static bool classof(const BuiltinType *) { return true; }
};
-/// PointerType - C99 6.7.4.1 - Pointer Declarators.
+/// PointerType - C99 6.7.5.1 - Pointer Declarators.
///
class PointerType : public Type {
TypeRef PointeeType;
@@ -203,7 +203,7 @@
static bool classof(const PointerType *) { return true; }
};
-/// PointerType - C99 6.7.4.2 - Array Declarators.
+/// PointerType - C99 6.7.5.2 - Array Declarators.
///
class ArrayType : public Type {
public:
@@ -241,6 +241,86 @@
static bool classof(const ArrayType *) { return true; }
};
+/// FunctionType - C99 6.7.5.3 - Array Declarators. This is the common base
+/// class of FunctionTypeNoProto and FunctionTypeProto.
+///
+class FunctionType : public Type {
+ /// SubClassData - This field is owned by the subclass, put here to pack
+ /// tightly with the ivars in Type.
+ bool SubClassData : 1;
+
+ // The type returned by the function.
+ TypeRef ResultType;
+protected:
+ FunctionType(TypeClass tc, TypeRef res, bool SubclassInfo, Type *Canonical)
+ : Type(tc, Canonical), SubClassData(SubclassInfo), ResultType(res) {}
+ bool getSubClassData() const { return SubClassData; }
+public:
+
+ TypeRef getResultType() const { return ResultType; }
+
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionNoProto ||
+ T->getTypeClass() == FunctionProto;
+ }
+ static bool classof(const FunctionType *) { return true; }
+};
+
+/// FunctionTypeNoProto - Represents a K&R-style 'int foo()' function, which has
+/// no information available about its arguments.
+class FunctionTypeNoProto : public FunctionType {
+ FunctionTypeNoProto(TypeRef Result, Type *Canonical)
+ : FunctionType(FunctionNoProto, Result, false, Canonical) {}
+ friend class ASTContext; // ASTContext creates these.
+public:
+ // No additional state past what FunctionType provides.
+
+ virtual void getAsString(std::string &InnerString) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionNoProto;
+ }
+ static bool classof(const FunctionTypeNoProto *) { return true; }
+};
+
+/// FunctionTypeProto - Represents a prototype with argument type info, e.g.
+/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
+/// arguments, not as having a single void argument.
+class FunctionTypeProto : public FunctionType {
+ FunctionTypeProto(TypeRef Result, TypeRef *ArgArray, unsigned numArgs,
+ bool isVariadic, Type *Canonical)
+ : FunctionType(FunctionProto, Result, isVariadic, Canonical),
+ NumArgs(numArgs) {
+ for (unsigned i = 0; i != numArgs; ++i)
+ ArgInfo[i] = ArgArray[i];
+ }
+
+ /// NumArgs - The number of arguments this function has, not counting '...'.
+ unsigned NumArgs;
+
+ /// ArgInfo - This array holds the argument types. Note that this is actually
+ /// a variable-sized array, so it must be the last instance variable in the
+ /// class.
+ TypeRef ArgInfo[1];
+ friend class ASTContext; // ASTContext creates these.
+public:
+ unsigned getNumArgs() const { return NumArgs; }
+ TypeRef getArgType(unsigned i) const {
+ assert(i < NumArgs && "Invalid argument number!");
+ return ArgInfo[i];
+ }
+
+ bool isVariadic() const { return getSubClassData(); }
+
+ virtual void getAsString(std::string &InnerString) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionProto;
+ }
+ static bool classof(const FunctionTypeProto *) { return true; }
+};
+
class TypeNameType : public Type {
TypeDecl *Decl;
More information about the cfe-commits
mailing list