move GetBuiltinType from Builtin::Context to ASTContext.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73316 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index fb28fd4..4891fd3 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3375,3 +3375,203 @@
 ExternalASTSource::~ExternalASTSource() { }
 
 void ExternalASTSource::PrintStats() { }
+
+
+//===----------------------------------------------------------------------===//
+//                          Builtin Type Computation
+//===----------------------------------------------------------------------===//
+
+/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
+/// pointer over the consumed characters.  This returns the resultant type.
+static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, 
+                                  ASTContext::GetBuiltinTypeError &Error,
+                                  bool AllowTypeModifiers = true) {
+  // Modifiers.
+  int HowLong = 0;
+  bool Signed = false, Unsigned = false;
+  
+  // Read the modifiers first.
+  bool Done = false;
+  while (!Done) {
+    switch (*Str++) {
+    default: Done = true; --Str; break; 
+    case 'S':
+      assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
+      assert(!Signed && "Can't use 'S' modifier multiple times!");
+      Signed = true;
+      break;
+    case 'U':
+      assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
+      assert(!Unsigned && "Can't use 'S' modifier multiple times!");
+      Unsigned = true;
+      break;
+    case 'L':
+      assert(HowLong <= 2 && "Can't have LLLL modifier");
+      ++HowLong;
+      break;
+    }
+  }
+
+  QualType Type;
+  
+  // Read the base type.
+  switch (*Str++) {
+  default: assert(0 && "Unknown builtin type letter!");
+  case 'v':
+    assert(HowLong == 0 && !Signed && !Unsigned &&
+           "Bad modifiers used with 'v'!");
+    Type = Context.VoidTy;
+    break;
+  case 'f':
+    assert(HowLong == 0 && !Signed && !Unsigned &&
+           "Bad modifiers used with 'f'!");
+    Type = Context.FloatTy;
+    break;
+  case 'd':
+    assert(HowLong < 2 && !Signed && !Unsigned &&
+           "Bad modifiers used with 'd'!");
+    if (HowLong)
+      Type = Context.LongDoubleTy;
+    else
+      Type = Context.DoubleTy;
+    break;
+  case 's':
+    assert(HowLong == 0 && "Bad modifiers used with 's'!");
+    if (Unsigned)
+      Type = Context.UnsignedShortTy;
+    else
+      Type = Context.ShortTy;
+    break;
+  case 'i':
+    if (HowLong == 3)
+      Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty;
+    else if (HowLong == 2)
+      Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
+    else if (HowLong == 1)
+      Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
+    else
+      Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy;
+    break;
+  case 'c':
+    assert(HowLong == 0 && "Bad modifiers used with 'c'!");
+    if (Signed)
+      Type = Context.SignedCharTy;
+    else if (Unsigned)
+      Type = Context.UnsignedCharTy;
+    else
+      Type = Context.CharTy;
+    break;
+  case 'b': // boolean
+    assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!");
+    Type = Context.BoolTy;
+    break;
+  case 'z':  // size_t.
+    assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!");
+    Type = Context.getSizeType();
+    break;
+  case 'F':
+    Type = Context.getCFConstantStringType();
+    break;
+  case 'a':
+    Type = Context.getBuiltinVaListType();
+    assert(!Type.isNull() && "builtin va list type not initialized!");
+    break;
+  case 'A':
+    // This is a "reference" to a va_list; however, what exactly
+    // this means depends on how va_list is defined. There are two
+    // different kinds of va_list: ones passed by value, and ones
+    // passed by reference.  An example of a by-value va_list is
+    // x86, where va_list is a char*. An example of by-ref va_list
+    // is x86-64, where va_list is a __va_list_tag[1]. For x86,
+    // we want this argument to be a char*&; for x86-64, we want
+    // it to be a __va_list_tag*.
+    Type = Context.getBuiltinVaListType();
+    assert(!Type.isNull() && "builtin va list type not initialized!");
+    if (Type->isArrayType()) {
+      Type = Context.getArrayDecayedType(Type);
+    } else {
+      Type = Context.getLValueReferenceType(Type);
+    }
+    break;
+  case 'V': {
+    char *End;
+    
+    unsigned NumElements = strtoul(Str, &End, 10);
+    assert(End != Str && "Missing vector size");
+    
+    Str = End;
+    
+    QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
+    Type = Context.getVectorType(ElementType, NumElements);
+    break;
+  }
+  case 'P': {
+    IdentifierInfo *II = &Context.Idents.get("FILE");
+    DeclContext::lookup_result Lookup 
+      = Context.getTranslationUnitDecl()->lookup(Context, II);
+    if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) {
+      Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first));
+      break;
+    }
+    else {
+      Error = ASTContext::GE_Missing_FILE;
+      return QualType();
+    }
+  }
+  }
+  
+  if (!AllowTypeModifiers)
+    return Type;
+  
+  Done = false;
+  while (!Done) {
+    switch (*Str++) {
+      default: Done = true; --Str; break;
+      case '*':
+        Type = Context.getPointerType(Type);
+        break;
+      case '&':
+        Type = Context.getLValueReferenceType(Type);
+        break;
+      // FIXME: There's no way to have a built-in with an rvalue ref arg.
+      case 'C':
+        Type = Type.getQualifiedType(QualType::Const);
+        break;
+    }
+  }
+  
+  return Type;
+}
+
+/// GetBuiltinType - Return the type for the specified builtin.
+QualType ASTContext::GetBuiltinType(unsigned id,
+                                    GetBuiltinTypeError &Error) {
+  const char *TypeStr = BuiltinInfo.GetTypeString(id);
+  
+  llvm::SmallVector<QualType, 8> ArgTypes;
+  
+  Error = GE_None;
+  QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error);
+  if (Error != GE_None)
+    return QualType();
+  while (TypeStr[0] && TypeStr[0] != '.') {
+    QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error);
+    if (Error != GE_None)
+      return QualType();
+
+    // Do array -> pointer decay.  The builtin should use the decayed type.
+    if (Ty->isArrayType())
+      Ty = getArrayDecayedType(Ty);
+   
+    ArgTypes.push_back(Ty);
+  }
+
+  assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
+         "'.' should only occur at end of builtin type list!");
+
+  // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
+  if (ArgTypes.size() == 0 && TypeStr[0] == '.')
+    return getFunctionNoProtoType(ResType);
+  return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
+                         TypeStr[0] == '.', 0);
+}