[cfe-commits] r46132 - in /cfe/trunk: 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
Chris Lattner
clattner at apple.com
Tue Jan 29 20:46:26 PST 2008
On Jan 17, 2008, at 9:46 AM, Nate Begeman wrote:
> URL: http://llvm.org/viewvc/llvm-project?rev=46132&view=rev
> Log:
> Implement basic overload support via a new builtin,
> __builtin_overload.
Hey Nate,
I'm finally starting to catch up on clang-mail and you're at the top
of the list. :)
> __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);
Ok, nice! Please add a couple tests to the testsuite though. It is
very useful to have testcases and documentation for things that are
clang extensions. Some more nit picks:
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Thu Jan 17 11:46:27 2008
> @@ -1124,6 +1124,57 @@
> 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.
It would be good to mention here that the function arguments are
required to have pointer to function type.
> +class OverloadExpr : public Expr {
> + Expr **SubExprs;
Please describe what the subexprs are here. Is SubExprs[0] the
constant expression?
>
> + unsigned NumArgs;
> + unsigned FnIndex;
Can FnIndex be computed lazily from SubExprs[0] instead of being
stored in the AST?
> + typedef Expr * const *arg_const_iterator;
> + arg_const_iterator arg_begin() const { return SubExprs+1; }
Why does arg_begin skip the first element here? What is element 0?
> + /// getNumArgs - Return the number of actual arguments to this
> call.
> + ///
> + unsigned getNumArgs() const { return NumArgs; }
From context, I don't think this is right. Does this include the
constant expression and the arguments and the functions? Or just a
subset of these? Please clarify in the comment.
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/CodeGen/CGExprScalar.cpp (original)
> +++ cfe/trunk/CodeGen/CGExprScalar.cpp Thu Jan 17 11:46:27 2008
> @@ -991,6 +992,10 @@
> Visit(E->isConditionTrue(CGF.getContext()) ? E->getLHS() : E-
> >getRHS());
> }
>
> +Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) {
> + return CGF.EmitCallExpr(E->getFn(), E->arg_begin()).getScalarVal();
> +}
I think you need similar functionality it CGExpr(Complex|Agg) to
handle complex and aggregate returns.
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/Parse/ParseExpr.cpp (original)
> +++ cfe/trunk/Parse/ParseExpr.cpp Thu Jan 17 11:46:27 2008
> @@ -909,6 +911,44 @@
> ConsumeParen());
> break;
> }
> + case tok::kw___builtin_overload: {
> + llvm::SmallVector<ExprTy*, 8> ArgExprs;
> + llvm::SmallVector<SourceLocation, 8> CommaLocs;
> +
...
> + // __builtin_overload requires at least 2 arguments
> + if (ArgExprs.size() < 2) {
> + Diag(Tok, diag::err_typecheck_call_too_few_args);
> + return ExprResult(true);
> + }
I think it would make sense to do this in Sema. That all the
correctness checking is in one place, making it more obvious that the
access to Args[0] is safe.
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- cfe/trunk/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/Sema/SemaExpr.cpp Thu Jan 17 11:46:27 2008
> +/// ExprsCompatibleWithFnType - return true if the Exprs in array
> Args have
> +/// QualTypes that match the QualTypes of the arguments of the
> FnType.
Mention in this comment that we already validated that the #args
matches the number of args in FnType. Also, 'compatible' is a highly
loaded word in the standard that doesn't mean 'exact match'. How
about calling it "ExprsMatchFnType"?
>
> +static bool ExprsCompatibleWithFnType(Expr **Args,
> FunctionTypeProto *FnType) {
can the arguments be 'const'?
>
> + unsigned NumParams = FnType->getNumArgs();
> + for (unsigned i = 0; i != NumParams; ++i)
> + if (Args[i]->getType() != FnType->getArgType(i))
This needs to use getType().getCanonicalType() to avoid problems with
typedef etc.
> +
> +Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned
> NumArgs,
> + SourceLocation *CommaLocs,
> + SourceLocation BuiltinLoc,
> + SourceLocation RParenLoc) {
> + assert((NumArgs > 1) && "Too few arguments for OverloadExpr!");
> + // Figure out the return type, by matching the args to one of the
> functions
> + // listed after the paramters.
typo '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());
This won't work 100% in the face of typedefs. Please dyncast "PT-
>getPointeeType().getCanonicalType()", which will strip off the
typedef'ness.
> + // 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;
I think it makes sense to emit an error about these two cases. It
doesn't ever make sense to use:
__builtin_overload(1, x, fmod)
of:
__builtin_overload(1, x, 42)
for example, because fmod takes two parameters, and the int isn't a
function parameter. This should be a hard error instead of silently
ignoring it.
>
> +
> + // Scan the parameter list for the FunctionType, checking the
> QualType of
> + // each paramter against the QualTypes of the arguments to the
> builtin.
typo paramter
> + // 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() + " ";
This adds an extraneous ' ' at the end of string :)
Overall, very nice Nate!
-Chris
More information about the cfe-commits
mailing list