[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