]> granicus.if.org Git - clang/commitdiff
Add code generation and sema checking for __builtin_va_arg.
authorAnders Carlsson <andersca@mac.com>
Mon, 15 Oct 2007 20:28:48 +0000 (20:28 +0000)
committerAnders Carlsson <andersca@mac.com>
Mon, 15 Oct 2007 20:28:48 +0000 (20:28 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43006 91177308-0d34-0410-b5e6-96231b3b80d8

AST/Expr.cpp
AST/StmtPrinter.cpp
CodeGen/CGExprScalar.cpp
Parse/ParseExpr.cpp
Sema/Sema.h
Sema/SemaDecl.cpp
Sema/SemaExpr.cpp
include/clang/AST/Expr.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h

index ac8df82aec847c2f0518e2a33dbfbd86f2f776ad..eefd8fafe688564af4a90078c8e6028efcf10a99 100644 (file)
@@ -1054,6 +1054,15 @@ Stmt::child_iterator ChooseExpr::child_end() {
   return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
 }
 
+// VAArgExpr
+Stmt::child_iterator VAArgExpr::child_begin() {
+  return reinterpret_cast<Stmt**>(&Val);
+}
+
+Stmt::child_iterator VAArgExpr::child_end() {
+  return reinterpret_cast<Stmt**>(&Val)+1;
+}
+
 // InitListExpr
 Stmt::child_iterator InitListExpr::child_begin() {
   return reinterpret_cast<Stmt**>(&InitExprs[0]);
index ff4b54bd8d1d6bd39429b0238a4b7a18df8bb61c..9b4ad11ec6f3bcd87331460f8e43038d5c696d7f 100644 (file)
@@ -587,6 +587,14 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
   OS << " }";
 }
 
+void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
+  OS << "va_arg(";
+  PrintExpr(Node->getSubExpr());
+  OS << ", ";
+  OS << Node->getType().getAsString();
+  OS << ")";
+}
+
 // C++
 
 void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) {
index 97efa33fc5a3fb29e76909d9674b0af4748a6815..e73ce616683d992983230c1101a11a0797cd6755 100644 (file)
@@ -16,6 +16,7 @@
 #include "clang/AST/AST.h"
 #include "llvm/Constants.h"
 #include "llvm/Function.h"
+#include "llvm/Intrinsics.h"
 #include "llvm/Support/Compiler.h"
 using namespace clang;
 using namespace CodeGen;
@@ -241,6 +242,7 @@ public:
   // Other Operators.
   Value *VisitConditionalOperator(const ConditionalOperator *CO);
   Value *VisitChooseExpr(ChooseExpr *CE);
+  Value *VisitVAArgExpr(VAArgExpr *VE);
   Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
     return CGF.EmitObjCStringLiteral(E);
   }
@@ -892,6 +894,14 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
   return Visit(CondVal != 0 ? E->getLHS() : E->getRHS());
 }
 
+Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE)
+{
+  llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress();
+
+  llvm::Value *V = Builder.CreateVAArg(ArgValue, ConvertType(VE->getType()));  
+  return V;
+}
+
 //===----------------------------------------------------------------------===//
 //                         Entry Point into this File
 //===----------------------------------------------------------------------===//
index 8a576edab033fbf5f0aa030a19c1a841343d17ed..c69d4d2d95103eda6f8dee9f1015ab7d9d5dbad4 100644 (file)
@@ -793,9 +793,9 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
 
   switch (T) {
   default: assert(0 && "Not a builtin primary expression!");
-  case tok::kw___builtin_va_arg:
-    Res = ParseAssignmentExpression();
-    if (Res.isInvalid) {
+  case tok::kw___builtin_va_arg: {
+    ExprResult Expr = ParseAssignmentExpression();
+    if (Expr.isInvalid) {
       SkipUntil(tok::r_paren);
       return Res;
     }
@@ -803,11 +803,15 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
     if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
       return ExprResult(true);
 
-    ParseTypeName();
+    TypeTy *Ty = ParseTypeName();
     
-    MatchRHSPunctuation(tok::r_paren, LParenLoc);
+    if (Tok.isNot(tok::r_paren)) {
+      Diag(Tok, diag::err_expected_rparen);
+      return ExprResult(true);
+    }
+    Res = Actions.ActOnVAArg(StartLoc, Expr.Val, Ty, ConsumeParen());
     break;
-    
+  }
   case tok::kw___builtin_offsetof: {
     SourceLocation TypeLoc = Tok.getLocation();
     TypeTy *Ty = ParseTypeName();
index a7db5b9d2ab0aac9802386ef8b32d577ae672fbd..c45bbf8e5dd4c17050dd2963d68298e4f88cc468 100644 (file)
@@ -418,6 +418,11 @@ public:
                                      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 @@ private:
                                           unsigned NewWidth, bool NewSign,
                                           SourceLocation Loc, unsigned DiagID);
   
+  void InitBuiltinVaListType();
+  
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
   private:
index 59a2d1d547668b9795915f4558067dc1b226e2b9..62f3fabe7d263f4d61e9f3de86e00c5df1e1fbe0 100644 (file)
@@ -146,23 +146,29 @@ ScopedDecl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI,
   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);
index 471312baf06cb6c02a8432b57b2a78f1c13d3103..9142a257f44b3665a27984d8e882227b1fbfc0d2 100644 (file)
@@ -1859,6 +1859,30 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
   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);
index 4eb96ad89f79f14f814d16d9a846607007c9932c..26771d66421634f0a3181ab67bffa70d3f29de75 100644 (file)
@@ -976,6 +976,32 @@ public:
   virtual child_iterator child_end();
 };
 
+/// VAArgExpr, used for the builtin function __builtin_va_start.
+class VAArgExpr : public Expr {
+  Expr *Val;
+  SourceLocation BuiltinLoc, RParenLoc;
+public:
+  VAArgExpr(SourceLocation BLoc, Expr* e, QualType t, SourceLocation RPLoc)
+    : Expr(VAArgExprClass, t),
+      Val(e),
+      BuiltinLoc(BLoc),
+      RParenLoc(RPLoc) { }
+  
+  const Expr *getSubExpr() const { return Val; }
+  Expr *getSubExpr() { return Val; }
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(BuiltinLoc, RParenLoc);
+  }  
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == VAArgExprClass;
+  }
+  static bool classof(const VAArgExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();  
+};
+  
 /// InitListExpr, used for struct and array initializers.
 class InitListExpr : public Expr {
   Expr **InitExprs;
index d505312aada7056aa2a64afe805fe143b915908a..5c4743faa98cbe24dbdba129b8df6ca758fbd734 100644 (file)
@@ -66,6 +66,7 @@ STMT(49, ImplicitCastExpr      , Expr)
 STMT(50, CompoundLiteralExpr   , Expr)
 STMT(51, OCUVectorElementExpr  , Expr)
 STMT(52, InitListExpr          , Expr)
+STMT(53, VAArgExpr             , Expr)
 
 // GNU Extensions.
 STMT(55, AddrLabelExpr        , Expr)
index e2b055b783ffaa94640233b40ce67ae042d9e5a5..5325c025efa4a655276a5eb2c76fa73add3606ab 100644 (file)
@@ -863,7 +863,9 @@ DIAG(err_va_start_used_in_non_variadic_function, ERROR,
     "'va_start' used in function with fixed args")
 DIAG(warn_second_parameter_of_va_start_not_last_named_argument, WARNING,
     "second parameter of 'va_start' not last named argument")
-
+DIAG(err_first_argument_to_va_arg_not_of_type_va_list, ERROR,
+    "first argument to 'va_arg' is of type '%0' and not 'va_list'")
+  
 DIAG(warn_return_missing_expr, WARNING,
      "non-void function '%0' should return a value")
 DIAG(ext_return_missing_expr, EXTENSION,
index 2113871f39621e638f04a94ab54731a10eabf1c4..cd48862b089e59d08175da38aa5d55bbdac836f7 100644 (file)
@@ -425,6 +425,13 @@ public:
     return 0;
   }
 
+  // __builtin_va_arg(expr, type)
+  virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+                                ExprTy *expr, TypeTy *type,
+                                SourceLocation RPLoc) {
+    return 0;
+  }
+  
   //===------------------------- C++ Expressions --------------------------===//
   
   /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.