]> granicus.if.org Git - clang/commitdiff
Implement basic overload support via a new builtin, __builtin_overload.
authorNate Begeman <natebegeman@mac.com>
Thu, 17 Jan 2008 17:46:27 +0000 (17:46 +0000)
committerNate Begeman <natebegeman@mac.com>
Thu, 17 Jan 2008 17:46:27 +0000 (17:46 +0000)
__builtin_overload takes 2 or more arguments:
0) a non-zero constant-expr for the number of arguments the overloaded
   functions will take
1) the arguments to pass to the matching overloaded function
2) a list of functions to match.

The return type of __builtin_overload is inferred from the function whose args
match the types of the arguments passed to the builtin.  For example:

float a;
float sinf(float);
int   sini(int);

float b = __builtin_overload(1, a, sini, sinf);

Says that we are overloading functions that take one argument, and trying to
pass an argument of the same type as 'a'.  sini() does not match since it takes
and argument of type int.  sinf does match, so at codegen time this will turn
into float b = sinf(a);

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46132 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
AST/Expr.cpp
AST/StmtPrinter.cpp
CodeGen/CGBuiltin.cpp
CodeGen/CGExpr.cpp
CodeGen/CGExprScalar.cpp
CodeGen/CodeGenFunction.h
Parse/ParseExpr.cpp
Sema/Sema.h
Sema/SemaExpr.cpp
include/clang/AST/Expr.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
include/clang/Basic/TokenKinds.def
include/clang/Parse/Action.h

index 0e1eecd7d79caeaf0aaf4c35bc162c96b13c026b..8aa5eed80b4e2b1f4f12b95424607bc9becc891a 100644 (file)
@@ -78,6 +78,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) {
 // Postfix Operators.
 //===----------------------------------------------------------------------===//
 
+
 CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
                    SourceLocation rparenloc)
   : Expr(CallExprClass, t), NumArgs(numargs) {
@@ -1238,6 +1239,14 @@ Stmt::child_iterator ChooseExpr::child_end() {
   return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
 }
 
+// OverloadExpr
+Stmt::child_iterator OverloadExpr::child_begin() {
+  return reinterpret_cast<Stmt**>(&SubExprs[0]);
+}
+Stmt::child_iterator OverloadExpr::child_end() {
+  return reinterpret_cast<Stmt**>(&SubExprs[NumArgs]);
+}
+
 // VAArgExpr
 Stmt::child_iterator VAArgExpr::child_begin() {
   return reinterpret_cast<Stmt**>(&Val);
index 6bfe7352119db7f2c08bebdb97ec355f91b4bb72..81bad22a7e7e9e9eddab24d59afb27f795cad47f 100644 (file)
@@ -733,6 +733,15 @@ void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
   OS << ")";
 }
 
+void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) {
+  OS << "__builtin_overload(";
+  for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i) {
+    if (i) OS << ", ";
+    PrintExpr(Node->getArg(i));
+  }
+  OS << ")";
+}
+
 void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
   OS << "{ ";
   for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
index cd3c2e6cf2739a472ac3888b7ee068d955dd0496..b782b223f630d78ce2d0e833723ef254382fef72 100644 (file)
@@ -29,7 +29,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
   switch (BuiltinID) {
   default: {
     if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
-      return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), E);
+      return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), E->getType(),
+                          E->arg_begin());
   
     // See if we have a target specific intrinsic.
     Intrinsic::ID IntrinsicID;
index 0fe25c8d168a129dd07100fc9f3cb941200c81ac..ad9e15a7cabddeb3646515ee0f70845e73e70f4d 100644 (file)
@@ -450,7 +450,12 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
           return EmitBuiltinExpr(builtinID, E);
         
   llvm::Value *Callee = EmitScalarExpr(E->getCallee());
-  return EmitCallExpr(Callee, E);
+  return EmitCallExpr(Callee, E->getType(), E->arg_begin());
+}
+
+RValue CodeGenFunction::EmitCallExpr(Expr *FnExpr, Expr *const *Args) {
+  llvm::Value *Callee = EmitScalarExpr(FnExpr);
+  return EmitCallExpr(Callee, FnExpr->getType(), Args);
 }
 
 LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -459,45 +464,42 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
   return LValue::MakeAddr(RV.getAggregateAddr());
 }
 
-RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, const CallExpr *E) {
+RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType, 
+                                     Expr *const *ArgExprs) {
   // The callee type will always be a pointer to function type, get the function
   // type.
-  QualType CalleeTy = E->getCallee()->getType();
-  CalleeTy = cast<PointerType>(CalleeTy.getCanonicalType())->getPointeeType();
-  
-  // Get information about the argument types.
-  FunctionTypeProto::arg_type_iterator ArgTyIt = 0, ArgTyEnd = 0;
+  FnType = cast<PointerType>(FnType.getCanonicalType())->getPointeeType();
+  QualType ResultType = cast<FunctionType>(FnType)->getResultType();
   
   // Calling unprototyped functions provides no argument info.
-  if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(CalleeTy)) {
-    ArgTyIt  = FTP->arg_type_begin();
-    ArgTyEnd = FTP->arg_type_end();
-  }
+  unsigned NumArgs = 0;
+  if (const FunctionTypeProto *FTP = dyn_cast<FunctionTypeProto>(FnType))
+    NumArgs = FTP->getNumArgs();
   
   llvm::SmallVector<llvm::Value*, 16> Args;
   
   // Handle struct-return functions by passing a pointer to the location that
   // we would like to return into.
-  if (hasAggregateLLVMType(E->getType())) {
+  if (hasAggregateLLVMType(ResultType)) {
     // Create a temporary alloca to hold the result of the call. :(
-    Args.push_back(CreateTempAlloca(ConvertType(E->getType())));
+    Args.push_back(CreateTempAlloca(ConvertType(ResultType)));
     // FIXME: set the stret attribute on the argument.
   }
   
-  for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
-    QualType ArgTy = E->getArg(i)->getType();
+  for (unsigned i = 0, e = NumArgs; i != e; ++i) {
+    QualType ArgTy = ArgExprs[i]->getType();
     
     if (!hasAggregateLLVMType(ArgTy)) {
       // Scalar argument is passed by-value.
-      Args.push_back(EmitScalarExpr(E->getArg(i)));
+      Args.push_back(EmitScalarExpr(ArgExprs[i]));
     } else if (ArgTy->isComplexType()) {
       // Make a temporary alloca to pass the argument.
       llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
-      EmitComplexExprIntoAddr(E->getArg(i), DestMem, false);
+      EmitComplexExprIntoAddr(ArgExprs[i], DestMem, false);
       Args.push_back(DestMem);
     } else {
       llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));
-      EmitAggExpr(E->getArg(i), DestMem, false);
+      EmitAggExpr(ArgExprs[i], DestMem, false);
       Args.push_back(DestMem);
     }
   }
@@ -505,14 +507,14 @@ RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, const CallExpr *E) {
   llvm::Value *V = Builder.CreateCall(Callee, &Args[0], &Args[0]+Args.size());
   if (V->getType() != llvm::Type::VoidTy)
     V->setName("call");
-  else if (E->getType()->isComplexType())
+  else if (ResultType->isComplexType())
     return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
-  else if (hasAggregateLLVMType(E->getType()))
+  else if (hasAggregateLLVMType(ResultType))
     // Struct return.
     return RValue::getAggregate(Args[0]);
   else {
     // void return.
-    assert(E->getType()->isVoidType() && "Should only have a void expr here");
+    assert(ResultType->isVoidType() && "Should only have a void expr here");
     V = 0;
   }
       
index a76f1e15509ab0de7c00f9da0df783715c1581dc..410284a7b8e7d412290f16686729271fe19de2ea 100644 (file)
@@ -282,6 +282,7 @@ public:
   // Other Operators.
   Value *VisitConditionalOperator(const ConditionalOperator *CO);
   Value *VisitChooseExpr(ChooseExpr *CE);
+  Value *VisitOverloadExpr(OverloadExpr *OE);
   Value *VisitVAArgExpr(VAArgExpr *VE);
   Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
     return CGF.EmitObjCStringLiteral(E);
@@ -991,6 +992,10 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
     Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() : E->getRHS());
 }
 
+Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) {
+  return CGF.EmitCallExpr(E->getFn(), E->arg_begin()).getScalarVal();
+}
+
 Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
   llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress();
 
index 216b7cd71a695efacca6d19c9ec427aed141e6f3..55a02a89b96e9d79e2b497a53b7d258e857010ab 100644 (file)
@@ -388,7 +388,8 @@ public:
   //===--------------------------------------------------------------------===//
 
   RValue EmitCallExpr(const CallExpr *E);
-  RValue EmitCallExpr(llvm::Value *Callee, const CallExpr *E);
+  RValue EmitCallExpr(Expr *FnExpr, Expr *const *Args);
+  RValue EmitCallExpr(llvm::Value *Callee, QualType FnType, Expr *const *Args);
   RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
 
   llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
index 5046f28d4632b3f5ac1dd321e4386578b9dd222e..c7b8ea62e7fe4bfe651cd78afb7bc12d5724d2b8 100644 (file)
@@ -550,6 +550,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
   case tok::kw___builtin_va_arg:
   case tok::kw___builtin_offsetof:
   case tok::kw___builtin_choose_expr:
+  case tok::kw___builtin_overload:
   case tok::kw___builtin_types_compatible_p:
     return ParseBuiltinPrimaryExpression();
   case tok::plusplus:      // unary-expression: '++' unary-expression
@@ -774,6 +775,7 @@ Parser::ExprResult Parser::ParseSizeofAlignofExpression() {
 /// [GNU]   '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
 ///                                     assign-expr ')'
 /// [GNU]   '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [CLANG] '__builtin_overload' '(' expr (',' expr)* ')'
 /// 
 /// [GNU] offsetof-member-designator:
 /// [GNU]   identifier
@@ -909,6 +911,44 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
                                   ConsumeParen());
     break;
   }
+  case tok::kw___builtin_overload: {
+    llvm::SmallVector<ExprTy*, 8> ArgExprs;
+    llvm::SmallVector<SourceLocation, 8> CommaLocs;
+
+    // For each iteration through the loop look for assign-expr followed by a
+    // comma.  If there is no comma, break and attempt to match r-paren.
+    if (Tok.isNot(tok::r_paren)) {
+      while (1) {
+        ExprResult ArgExpr = ParseAssignmentExpression();
+        if (ArgExpr.isInvalid) {
+          SkipUntil(tok::r_paren);
+          return ExprResult(true);
+        } else
+          ArgExprs.push_back(ArgExpr.Val);
+        
+        if (Tok.isNot(tok::comma))
+          break;
+        // Move to the next argument, remember where the comma was.
+        CommaLocs.push_back(ConsumeToken());
+      }
+    }
+    
+    // Attempt to consume the r-paren
+    if (Tok.isNot(tok::r_paren)) {
+      Diag(Tok, diag::err_expected_rparen);
+      SkipUntil(tok::r_paren);
+      return ExprResult(true);
+    }
+    
+    // __builtin_overload requires at least 2 arguments
+    if (ArgExprs.size() < 2) {
+      Diag(Tok, diag::err_typecheck_call_too_few_args);
+      return ExprResult(true);
+    }
+    Res = Actions.ActOnOverloadExpr(&ArgExprs[0], ArgExprs.size(), 
+                                    &CommaLocs[0], StartLoc, ConsumeParen());
+    break;
+  }
   case tok::kw___builtin_types_compatible_p:
     TypeTy *Ty1 = ParseTypeName();
     
index 7bac8b246562d95dd96c9fa34a7fadbf255d1058..38a37671b57fe08f4f3a4a63734812b7037cb958 100644 (file)
@@ -465,6 +465,12 @@ public:
                                      ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
                                      SourceLocation RPLoc);
   
+  // __builtin_overload(...)
+  virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs,
+                                       SourceLocation *CommaLocs,
+                                       SourceLocation BuiltinLoc, 
+                                       SourceLocation RParenLoc);
+  
   // __builtin_va_arg(expr, type)
   virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
                                 ExprTy *expr, TypeTy *type,
index 5d446dd01ea5f8fbbe74e44c8a0030a8f4e560f4..0c8e5e2315424831d6ed274749ceda6de09e3387 100644 (file)
@@ -892,7 +892,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&e) {
     ImpCastExprToType(e, Context.getPointerType(ary->getElementType()));
 }
 
-/// UsualUnaryConversion - Performs various conversions that are common to most
+/// UsualUnaryConversions - Performs various conversions that are common to most
 /// operators (C99 6.3). The conversions of array and function types are 
 /// sometimes surpressed. For example, the array->pointer conversion doesn't
 /// apply if the array is an argument to the sizeof or address (&) operators.
@@ -2074,6 +2074,76 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
   return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
 }
 
+/// ExprsCompatibleWithFnType - return true if the Exprs in array Args have
+/// QualTypes that match the QualTypes of the arguments of the FnType.
+static bool ExprsCompatibleWithFnType(Expr **Args, FunctionTypeProto *FnType) {
+  unsigned NumParams = FnType->getNumArgs();
+  for (unsigned i = 0; i != NumParams; ++i)
+    if (Args[i]->getType() != FnType->getArgType(i))
+      return false;
+  return true;
+}
+
+Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs,
+                                         SourceLocation *CommaLocs,
+                                         SourceLocation BuiltinLoc,
+                                         SourceLocation RParenLoc) {
+  assert((NumArgs > 1) && "Too few arguments for OverloadExpr!");
+
+  Expr **Args = reinterpret_cast<Expr**>(args);
+  // The first argument is required to be a constant expression.  It tells us
+  // the number of arguments to pass to each of the functions to be overloaded.
+  Expr *NParamsExpr = Args[0];
+  llvm::APSInt constEval(32);
+  SourceLocation ExpLoc;
+  if (!NParamsExpr->isIntegerConstantExpr(constEval, Context, &ExpLoc))
+    return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant,
+                NParamsExpr->getSourceRange());
+  
+  // Verify that the number of parameters is > 0
+  unsigned NumParams = constEval.getZExtValue();
+  if (NumParams == 0)
+    return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant,
+                NParamsExpr->getSourceRange());
+  // Verify that we have at least 1 + NumParams arguments to the builtin.
+  if ((NumParams + 1) > NumArgs)
+    return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+                SourceRange(BuiltinLoc, RParenLoc));
+
+  // Figure out the return type, by matching the args to one of the functions
+  // listed after the paramters.
+  for (unsigned i = NumParams + 1; i < NumArgs; ++i) {
+    // UsualUnaryConversions will convert the function DeclRefExpr into a 
+    // pointer to function.
+    Expr *Fn = UsualUnaryConversions(Args[i]);
+    FunctionTypeProto *FnType = 0;
+    if (const PointerType *PT = Fn->getType()->getAsPointerType())
+      FnType = dyn_cast<FunctionTypeProto>(PT->getPointeeType());
+    // The Expr type must be FunctionTypeProto, since FunctionTypeProto has no
+    // parameters, and the number of parameters must match the value passed to
+    // the builtin.
+    if (!FnType || (FnType->getNumArgs() != NumParams))
+      continue;
+
+    // Scan the parameter list for the FunctionType, checking the QualType of
+    // each paramter against the QualTypes of the arguments to the builtin.
+    // If they match, return a new OverloadExpr.
+    if (ExprsCompatibleWithFnType(Args+1, FnType))
+      return new OverloadExpr(Args, NumArgs, i, FnType->getResultType(),
+                              BuiltinLoc, RParenLoc);
+  }
+
+  // If we didn't find a matching function Expr in the __builtin_overload list
+  // the return an error.
+  std::string typeNames;
+  for (unsigned i = 0; i != NumParams; ++i)
+    typeNames += Args[i+1]->getType().getAsString() + " ";
+
+  return Diag(BuiltinLoc, diag::err_overload_no_match, typeNames,
+              SourceRange(BuiltinLoc, RParenLoc));
+}
+
 Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
                                   ExprTy *expr, TypeTy *type,
                                   SourceLocation RPLoc) {
index 0c2a3d085ceac5b4a51d508ee950fd8fb6e6d50c..3771c00281781d0e9ef84bd7365e951200c98ff5 100644 (file)
@@ -1124,6 +1124,57 @@ public:
   virtual child_iterator child_end();
 };
 
+/// OverloadExpr - Clang builtin-in function __builtin_overload.
+/// This AST node provides a way to overload functions in C
+/// i.e. float Z = __builtin_overload(2, X, Y, modf, mod, modl);
+/// would pick whichever of the functions modf, mod, and modl that took two
+/// arguments of the same type as X and Y.  
+class OverloadExpr : public Expr {
+  Expr **SubExprs;
+  unsigned NumArgs;
+  unsigned FnIndex;
+  SourceLocation BuiltinLoc;
+  SourceLocation RParenLoc;
+public:
+  OverloadExpr(Expr **args, unsigned narg, unsigned idx, QualType t, 
+               SourceLocation bloc, SourceLocation rploc)
+    : Expr(OverloadExprClass, t), NumArgs(narg), FnIndex(idx), BuiltinLoc(bloc), 
+      RParenLoc(rploc) {
+    SubExprs = new Expr*[narg];
+    for (unsigned i = 0; i != narg; ++i)
+      SubExprs[i] = args[i];
+  }
+  ~OverloadExpr() {
+    delete [] SubExprs;
+  }
+
+  typedef Expr * const *arg_const_iterator;
+  arg_const_iterator arg_begin() const { return SubExprs+1; }
+
+  /// getNumArgs - Return the number of actual arguments to this call.
+  ///
+  unsigned getNumArgs() const { return NumArgs; }
+  
+  /// getArg - Return the specified argument.
+  Expr *getArg(unsigned Arg) {
+    assert(Arg < NumArgs && "Arg access out of range!");
+    return SubExprs[Arg];
+  }
+  Expr *getFn() { return SubExprs[FnIndex]; }
+  
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(BuiltinLoc, RParenLoc);
+  }
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OverloadExprClass; 
+  }
+  static bool classof(const OverloadExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+};
+
 /// VAArgExpr, used for the builtin function __builtin_va_start.
 class VAArgExpr : public Expr {
   Expr *Val;
index 99262a71a03978d9c25786e6f3e3a67c85e6a346..89953b1315c583b8e0503f9695ab03a1e05acc85 100644 (file)
@@ -98,7 +98,10 @@ STMT(73, ObjCSelectorExpr     , Expr)
 STMT(74, ObjCProtocolExpr     , Expr)
 STMT(75, ObjCIvarRefExpr      , Expr)
 
-LAST_EXPR(75)
+// Clang Extensions.
+STMT(76, OverloadExpr         , Expr)
+
+LAST_EXPR(76)
 
 #undef STMT
 #undef FIRST_STMT
index 50815ec2163ff2621533f75240483f4873273f98..519af246ef59382e27d0062783cb96c94257d711 100644 (file)
@@ -834,6 +834,10 @@ DIAG(err_invalid_conversion_between_vector_and_integer, ERROR,
     "of different size")
 DIAG(err_invalid_conversion_between_vector_and_scalar, ERROR,
     "invalid conversion between vector type '%0' and scalar type '%1'")
+DIAG(err_overload_expr_requires_non_zero_constant, ERROR,
+     "overload requires a non-zero constant expression as first argument")
+DIAG(err_overload_no_match, ERROR,
+     "no matching overload found for arguments of type '%0'")
 
 // CHECK: printf format string errors
 DIAG(warn_printf_not_string_constant, WARNING,
index fcdf8c80a7b135f7a9330f96be3cc8213b768564..31d6bc74bb0717448ab1d3dc62af6ca79cd7a9b0 100644 (file)
@@ -289,6 +289,7 @@ KEYWORD(__null                      , NOTC90|NOTC99|EXTCPP|EXTCPP0x) // C++-only
 KEYWORD(__alignof                   , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 KEYWORD(__attribute                 , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 KEYWORD(__builtin_choose_expr       , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
+KEYWORD(__builtin_overload          , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 KEYWORD(__builtin_offsetof          , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 KEYWORD(__builtin_types_compatible_p, EXTC90|EXTC99|EXTCPP|EXTCPP0x)
 KEYWORD(__builtin_va_arg            , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
index 0e5ae2a79baf5e55445d793e7ddd7df717f231b0..d948b94b863bc71c6778c0bb79eb9259bf786955 100644 (file)
@@ -476,6 +476,14 @@ public:
                                      SourceLocation RPLoc) {
     return 0;
   }
+  // __builtin_overload(...)
+  virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs,
+                                       SourceLocation *CommaLocs,
+                                       SourceLocation BuiltinLoc, 
+                                       SourceLocation RPLoc) {
+    return 0;
+  }
+  
 
   // __builtin_va_arg(expr, type)
   virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,