From: Richard Smith Date: Thu, 10 Nov 2011 09:31:24 +0000 (+0000) Subject: Constant expression evaluation: support for constexpr member functions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6c95787b25c72a1c2421e349ef3459912362714a;p=clang Constant expression evaluation: support for constexpr member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144273 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 25c7a90caa..ca936f0ff8 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1029,8 +1029,9 @@ static bool EvaluateArgs(ArrayRef Args, ArgVector &ArgValues, } /// Evaluate a function call. -static bool HandleFunctionCall(ArrayRef Args, const Stmt *Body, - EvalInfo &Info, CCValue &Result) { +static bool HandleFunctionCall(const LValue *This, ArrayRef Args, + const Stmt *Body, EvalInfo &Info, + CCValue &Result) { // FIXME: Implement a proper call limit, along with a command-line flag. if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512) return false; @@ -1039,16 +1040,15 @@ static bool HandleFunctionCall(ArrayRef Args, const Stmt *Body, if (!EvaluateArgs(Args, ArgValues, Info)) return false; - // FIXME: Pass in 'this' for member functions. - const LValue *This = 0; CallStackFrame Frame(Info, This, ArgValues.data()); return EvaluateStmt(Result, Info, Body) == ESR_Returned; } /// Evaluate a constructor call. -static bool HandleConstructorCall(ArrayRef Args, +static bool HandleConstructorCall(const LValue &This, + ArrayRef Args, const CXXConstructorDecl *Definition, - EvalInfo &Info, const LValue &This, + EvalInfo &Info, APValue &Result) { if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512) return false; @@ -1305,39 +1305,64 @@ public: const Expr *Callee = E->getCallee(); QualType CalleeType = Callee->getType(); - // FIXME: Handle the case where Callee is a (parenthesized) MemberExpr for a - // non-static member function. - if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) - return DerivedError(E); - - if (!CalleeType->isFunctionType() && !CalleeType->isFunctionPointerType()) - return DerivedError(E); - - CCValue Call; - if (!Evaluate(Call, Info, Callee) || !Call.isLValue() || - !Call.getLValueBase() || !Call.getLValueOffset().isZero()) - return DerivedError(Callee); - const FunctionDecl *FD = 0; - if (const DeclRefExpr *DRE = dyn_cast(Call.getLValueBase())) - FD = dyn_cast(DRE->getDecl()); - else if (const MemberExpr *ME = dyn_cast(Call.getLValueBase())) + LValue *This = 0, ThisVal; + llvm::ArrayRef Args(E->getArgs(), E->getNumArgs()); + + // Extract function decl and 'this' pointer from the callee. + if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) { + const MemberExpr *ME = dyn_cast(Callee->IgnoreParens()); + // FIXME: Handle a BinaryOperator callee ('.*' or '->*'). + if (!ME) + return DerivedError(Callee); + if (ME->isArrow()) { + if (!EvaluatePointer(ME->getBase(), ThisVal, Info)) + return DerivedError(ME); + } else { + if (!EvaluateLValue(ME->getBase(), ThisVal, Info)) + return DerivedError(ME); + } + This = &ThisVal; FD = dyn_cast(ME->getMemberDecl()); - if (!FD) - return DerivedError(Callee); + if (!FD) + return DerivedError(ME); + } else if (CalleeType->isFunctionPointerType()) { + CCValue Call; + if (!Evaluate(Call, Info, Callee) || !Call.isLValue() || + !Call.getLValueBase() || !Call.getLValueOffset().isZero()) + return DerivedError(Callee); + + const Expr *Base = Call.getLValueBase(); + + if (const DeclRefExpr *DRE = dyn_cast(Base)) + FD = dyn_cast(DRE->getDecl()); + else if (const MemberExpr *ME = dyn_cast(Base)) + FD = dyn_cast(ME->getMemberDecl()); + if (!FD) + return DerivedError(Callee); + + // Overloaded operator calls to member functions are represented as normal + // calls with 'this' as the first argument. + const CXXMethodDecl *MD = dyn_cast(FD); + if (MD && !MD->isStatic()) { + if (!EvaluateLValue(Args[0], ThisVal, Info)) + return DerivedError(Args[0]); + This = &ThisVal; + Args = Args.slice(1); + } - // Don't call function pointers which have been cast to some other type. - if (!Info.Ctx.hasSameType(CalleeType->getPointeeType(), FD->getType())) - return DerivedError(E); + // Don't call function pointers which have been cast to some other type. + if (!Info.Ctx.hasSameType(CalleeType->getPointeeType(), FD->getType())) + return DerivedError(E); + } const FunctionDecl *Definition; Stmt *Body = FD->getBody(Definition); CCValue CCResult; APValue Result; - llvm::ArrayRef Args(E->getArgs(), E->getNumArgs()); if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() && - HandleFunctionCall(Args, Body, Info, CCResult) && + HandleFunctionCall(This, Args, Body, Info, CCResult) && CheckConstantExpression(CCResult, Result)) return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E); @@ -1890,8 +1915,8 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return Visit(ME->GetTemporaryExpr()); llvm::ArrayRef Args(E->getArgs(), E->getNumArgs()); - return HandleConstructorCall(Args, cast(Definition), - Info, This, Result); + return HandleConstructorCall(This, Args, cast(Definition), + Info, Result); } static bool EvaluateRecord(const Expr *E, const LValue &This, diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index e111c658b1..37d5876682 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -608,3 +608,35 @@ static_assert_fold(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant static_assert_fold((&(u[1]) + 1 + 1)->b == 3, ""); } + +namespace Complex { + +class complex { + int re, im; +public: + constexpr complex(int re = 0, int im = 0) : re(re), im(im) {} + constexpr complex(const complex &o) : re(o.re), im(o.im) {} + constexpr complex operator-() const { return complex(-re, -im); } + friend constexpr complex operator+(const complex &l, const complex &r) { + return complex(l.re + r.re, l.im + r.im); + } + friend constexpr complex operator-(const complex &l, const complex &r) { + return l + -r; + } + friend constexpr complex operator*(const complex &l, const complex &r) { + return complex(l.re * r.re - l.im * r.im, l.re * r.im + l.im * r.re); + } + friend constexpr bool operator==(const complex &l, const complex &r) { + return l.re == r.re && l.im == r.im; + } + constexpr int real() const { return re; } + constexpr int imag() const { return im; } +}; + +constexpr complex i = complex(0, 1); +constexpr complex k = (3 + 4*i) * (6 - 4*i); +static_assert_fold(k.real() == 34, ""); +static_assert_fold(k.imag() == 12, ""); +static_assert_fold(k - 34 == 12*i, ""); + +}