Add code generation and sema checking for __builtin_va_arg.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43006 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/Sema.h b/Sema/Sema.h
index a7db5b9..c45bbf8 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -418,6 +418,11 @@
                                      ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
                                      SourceLocation RPLoc);
   
+  // __builtin_va_arg(expr, type)
+  virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+                                ExprTy *expr, TypeTy *type,
+                                SourceLocation RPLoc);
+  
   /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
                                    SourceLocation LAngleBracketLoc, TypeTy *Ty,
@@ -624,6 +629,8 @@
                                           unsigned NewWidth, bool NewSign,
                                           SourceLocation Loc, unsigned DiagID);
   
+  void InitBuiltinVaListType();
+  
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
   private:
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 59a2d1d..62f3fab 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -146,23 +146,29 @@
   return 0;
 }
 
+void Sema::InitBuiltinVaListType()
+{
+  if (!Context.getBuiltinVaListType().isNull())
+    return;
+  
+  IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
+  ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary, 
+                                          SourceLocation(), TUScope);
+  TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
+  Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
+}
+
 /// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope.
 /// lazily create a decl for it.
 ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
                                       Scope *S) {
   Builtin::ID BID = (Builtin::ID)bid;
 
-  if ((BID == Builtin::BI__builtin_va_start ||
+  if (BID == Builtin::BI__builtin_va_start ||
        BID == Builtin::BI__builtin_va_copy ||
-       BID == Builtin::BI__builtin_va_end) &&
-      Context.getBuiltinVaListType().isNull()) {
-    IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
-    ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary, 
-                                          SourceLocation(), TUScope);
-    TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
-    Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
-  }
-  
+       BID == Builtin::BI__builtin_va_end)
+    InitBuiltinVaListType();
+    
   QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);  
   FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R,
                                        FunctionDecl::Extern, false, 0);
diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp
index 471312b..9142a25 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -1859,6 +1859,30 @@
   return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
 }
 
+Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
+                                  ExprTy *expr, TypeTy *type,
+                                  SourceLocation RPLoc)
+{
+  Expr *E = static_cast<Expr*>(expr);
+  QualType T = QualType::getFromOpaquePtr(type);
+
+  InitBuiltinVaListType();
+  
+  Sema::AssignmentCheckResult result;
+
+  result = CheckAssignmentConstraints(Context.getBuiltinVaListType(), 
+                                      E->getType());
+  if (result != Compatible)
+    return Diag(E->getLocStart(),
+                diag::err_first_argument_to_va_arg_not_of_type_va_list,
+                E->getType().getAsString(),
+                E->getSourceRange());
+  
+  // FIXME: Warn if a non-POD type is passed in.
+  
+  return new VAArgExpr(BuiltinLoc, E, T, RPLoc);
+}
+
 // TODO: Move this to SemaObjC.cpp
 Sema::ExprResult Sema::ParseObjCStringLiteral(ExprTy *string) {
   StringLiteral* S = static_cast<StringLiteral *>(string);