// Postfix Operators.
//===----------------------------------------------------------------------===//
+
CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
SourceLocation rparenloc)
: Expr(CallExprClass, t), NumArgs(numargs) {
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);
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) {
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;
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) {
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);
}
}
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;
}
// 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);
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();
//===--------------------------------------------------------------------===//
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);
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
/// [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
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();
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,
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.
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) {
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;
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
"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,
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)
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,