From: Nate Begeman Date: Wed, 30 Jan 2008 20:50:20 +0000 (+0000) Subject: Implement first round of feedback on __builtin_overload X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=67295d05c50ab0b5d1b0f9ef82a906701c348715;p=clang Implement first round of feedback on __builtin_overload git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46572 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 210d1a280b..e209db35ff 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -1291,7 +1291,7 @@ Stmt::child_iterator OverloadExpr::child_begin() { return reinterpret_cast(&SubExprs[0]); } Stmt::child_iterator OverloadExpr::child_end() { - return reinterpret_cast(&SubExprs[NumArgs]); + return reinterpret_cast(&SubExprs[NumExprs]); } // VAArgExpr diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index f04f9e5ba5..668902708d 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -743,9 +743,9 @@ void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) { OS << "__builtin_overload("; - for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i) { + for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { if (i) OS << ", "; - PrintExpr(Node->getArg(i)); + PrintExpr(Node->getExpr(i)); } OS << ")"; } diff --git a/CodeGen/CGExprComplex.cpp b/CodeGen/CGExprComplex.cpp index d96fbc77fc..b1de93570d 100644 --- a/CodeGen/CGExprComplex.cpp +++ b/CodeGen/CGExprComplex.cpp @@ -93,6 +93,7 @@ public: } ComplexPairTy VisitCallExpr(const CallExpr *E); ComplexPairTy VisitStmtExpr(const StmtExpr *E); + ComplexPairTy VisitOverloadExpr(const OverloadExpr *OE); // Operators. ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E, @@ -250,6 +251,11 @@ ComplexPairTy ComplexExprEmitter::VisitCallExpr(const CallExpr *E) { return CGF.EmitCallExpr(E).getComplexVal(); } +ComplexPairTy ComplexExprEmitter::VisitOverloadExpr(const OverloadExpr *E) { + return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), + E->getNumArgs(CGF.getContext())).getComplexVal(); +} + ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) { return CGF.EmitCompoundStmt(*E->getSubStmt(), true).getComplexVal(); } diff --git a/CodeGen/CGExprScalar.cpp b/CodeGen/CGExprScalar.cpp index 32a1b5386f..e7f58bb468 100644 --- a/CodeGen/CGExprScalar.cpp +++ b/CodeGen/CGExprScalar.cpp @@ -1012,7 +1012,8 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { } Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) { - return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), E->getNumArgs()).getScalarVal(); + return CGF.EmitCallExpr(E->getFn(), E->arg_begin(), + E->getNumArgs(CGF.getContext())).getScalarVal(); } Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index bb4cb519f0..86d6d772dd 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -2086,12 +2086,15 @@ 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 +/// ExprsMatchFnType - 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) { +/// The number of arguments has already been validated to match the number of +/// arguments in FnType. +static bool ExprsMatchFnType(Expr **Args, const FunctionTypeProto *FnType) { unsigned NumParams = FnType->getNumArgs(); for (unsigned i = 0; i != NumParams; ++i) - if (Args[i]->getType() != FnType->getArgType(i)) + if (Args[i]->getType().getCanonicalType() != + FnType->getArgType(i).getCanonicalType()) return false; return true; } @@ -2123,25 +2126,28 @@ Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs, SourceRange(BuiltinLoc, RParenLoc)); // Figure out the return type, by matching the args to one of the functions - // listed after the paramters. + // listed after the parameters. 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(PT->getPointeeType()); + if (const PointerType *PT = Fn->getType()->getAsPointerType()) { + QualType PointeeType = PT->getPointeeType().getCanonicalType(); + FnType = dyn_cast(PointeeType); + } // 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; + return Diag(Fn->getExprLoc(), diag::err_overload_incorrect_fntype, + Fn->getSourceRange()); // Scan the parameter list for the FunctionType, checking the QualType of - // each paramter against the QualTypes of the arguments to the builtin. + // each parameter against the QualTypes of the arguments to the builtin. // If they match, return a new OverloadExpr. - if (ExprsCompatibleWithFnType(Args+1, FnType)) + if (ExprsMatchFnType(Args+1, FnType)) return new OverloadExpr(Args, NumArgs, i, FnType->getResultType(), BuiltinLoc, RParenLoc); } @@ -2149,8 +2155,10 @@ Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs, // 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() + " "; + for (unsigned i = 0; i != NumParams; ++i) { + if (i != 0) typeNames += ", "; + typeNames += Args[i+1]->getType().getAsString(); + } return Diag(BuiltinLoc, diag::err_overload_no_match, typeNames, SourceRange(BuiltinLoc, RParenLoc)); diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index bdd5da3e40..820289976d 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1128,21 +1128,45 @@ public: }; /// 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. +/// This AST node provides a way to overload functions in C. +/// +/// The first argument is required to be a constant expression, for the number +/// of arguments passed to each candidate function. +/// +/// The next N arguments, where N is the value of the constant expression, +/// are the values to be passed as arguments. +/// +/// The rest of the arguments are values of pointer to function type, which +/// are the candidate functions for overloading. +/// +/// The result is a equivalent to a CallExpr taking N arguments to the +/// candidate function whose parameter types match the types of the N arguments. +/// +/// example: float Z = __builtin_overload(2, X, Y, modf, mod, modl); +/// If X and Y are long doubles, Z will assigned the result of modl(X, Y); +/// If X and Y are floats, Z will be assigned the result of modf(X, Y); class OverloadExpr : public Expr { + // SubExprs - the list of values passed to the __builtin_overload function. + // SubExpr[0] is a constant expression + // SubExpr[1-N] are the parameters to pass to the matching function call + // SubExpr[N-...] are the candidate functions, of type pointer to function. Expr **SubExprs; - unsigned NumArgs; + + // NumExprs - the size of the SubExprs array + unsigned NumExprs; + + // NumArgs - the number of arguments + + // The index of the matching candidate function 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) { + : Expr(OverloadExprClass, t), NumExprs(narg), FnIndex(idx), + BuiltinLoc(bloc), RParenLoc(rploc) { SubExprs = new Expr*[narg]; for (unsigned i = 0; i != narg; ++i) SubExprs[i] = args[i]; @@ -1151,19 +1175,31 @@ public: delete [] SubExprs; } + /// arg_begin - Return a pointer to the list of arguments that will be passed + /// to the matching candidate function, skipping over the initial constant + /// expression. 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; } + /// getNumArgs - Return the number of arguments to pass to the candidate + /// functions. + unsigned getNumArgs(ASTContext &Ctx) const { + llvm::APSInt constEval(32); + (void) SubExprs[0]->isIntegerConstantExpr(constEval, Ctx); + return constEval.getZExtValue(); + } + + /// getNumSubExprs - Return the size of the SubExprs array + unsigned getNumSubExprs() const { return NumExprs; } /// getArg - Return the specified argument. - Expr *getArg(unsigned Arg) { - assert(Arg < NumArgs && "Arg access out of range!"); - return SubExprs[Arg]; + Expr *getExpr(unsigned Expr) { + assert((Expr < NumExprs) && "Arg access out of range!"); + return SubExprs[Expr]; } - Expr *getFn() { return SubExprs[FnIndex]; } + + /// getFn - Return the matching candidate function for this OverloadExpr + Expr *getFn() const { return SubExprs[FnIndex]; } virtual SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 83e9e84dce..023b7c439d 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -844,6 +844,8 @@ 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_incorrect_fntype, ERROR, + "argument is not a function, or has wrong number of parameters") DIAG(err_overload_no_match, ERROR, "no matching overload found for arguments of type '%0'")