Author: rsmith Date: Thu Aug 27 21:43:42 2015 New Revision: 246263 URL: http://llvm.org/viewvc/llvm-project?rev=246263&view=rev Log: PR24597: Fix in-place evaluation of call expressions to provide a proper "this" pointer to an RVO construction of a returned object.
Modified: cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/test/PCH/cxx1y-default-initializer.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=246263&r1=246262&r2=246263&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Aug 27 21:43:42 2015 @@ -3248,12 +3248,21 @@ static bool EvaluateCond(EvalInfo &Info, return EvaluateAsBooleanCondition(Cond, Result, Info); } -static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, +/// \brief A location where the result (returned value) of evaluating a +/// statement should be stored. +struct StmtResult { + /// The APValue that should be filled in with the returned value. + APValue &Value; + /// The location containing the result, if any (used to support RVO). + const LValue *Slot; +}; + +static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, const SwitchCase *SC = nullptr); /// Evaluate the body of a loop, and translate the result as appropriate. -static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info, const Stmt *Body, const SwitchCase *Case = nullptr) { BlockScopeRAII Scope(Info); @@ -3272,7 +3281,7 @@ static EvalStmtResult EvaluateLoopBody(A } /// Evaluate a switch statement. -static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, const SwitchStmt *SS) { BlockScopeRAII Scope(Info); @@ -3329,7 +3338,7 @@ static EvalStmtResult EvaluateSwitch(APV } // Evaluate a statement. -static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, const SwitchCase *Case) { if (!Info.nextStep(S)) return ESR_Failed; @@ -3435,7 +3444,10 @@ static EvalStmtResult EvaluateStmt(APVal case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); FullExpressionRAII Scope(Info); - if (RetExpr && !Evaluate(Result, Info, RetExpr)) + if (RetExpr && + !(Result.Slot + ? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr) + : Evaluate(Result.Value, Info, RetExpr))) return ESR_Failed; return ESR_Returned; } @@ -3705,7 +3717,8 @@ static bool EvaluateArgs(ArrayRef<const static bool HandleFunctionCall(SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, ArrayRef<const Expr*> Args, const Stmt *Body, - EvalInfo &Info, APValue &Result) { + EvalInfo &Info, APValue &Result, + const LValue *ResultSlot) { ArgVector ArgValues(Args.size()); if (!EvaluateArgs(Args, ArgValues, Info)) return false; @@ -3740,7 +3753,8 @@ static bool HandleFunctionCall(SourceLoc return true; } - EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); + StmtResult Ret = {Result, ResultSlot}; + EvalStmtResult ESR = EvaluateStmt(Ret, Info, Body); if (ESR == ESR_Succeeded) { if (Callee->getReturnType()->isVoidType()) return true; @@ -3769,6 +3783,11 @@ static bool HandleConstructorCall(Source CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data()); + // FIXME: Creating an APValue just to hold a nonexistent return value is + // wasteful. + APValue RetVal; + StmtResult Ret = {RetVal, nullptr}; + // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); @@ -3777,7 +3796,7 @@ static bool HandleConstructorCall(Source if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) return false; } - return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; + return EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; } // For a trivial copy or move constructor, perform an APValue copy. This is @@ -3885,7 +3904,7 @@ static bool HandleConstructorCall(Source } return Success && - EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; + EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; } //===----------------------------------------------------------------------===// @@ -3897,11 +3916,12 @@ template <class Derived> class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> { private: + Derived &getDerived() { return static_cast<Derived&>(*this); } bool DerivedSuccess(const APValue &V, const Expr *E) { - return static_cast<Derived*>(this)->Success(V, E); + return getDerived().Success(V, E); } bool DerivedZeroInitialization(const Expr *E) { - return static_cast<Derived*>(this)->ZeroInitialization(E); + return getDerived().ZeroInitialization(E); } // Check whether a conditional operator with a non-constant condition is a @@ -4082,6 +4102,14 @@ public: } bool VisitCallExpr(const CallExpr *E) { + APValue Result; + if (!handleCallExpr(E, Result, nullptr)) + return false; + return DerivedSuccess(Result, E); + } + + bool handleCallExpr(const CallExpr *E, APValue &Result, + const LValue *ResultSlot) { const Expr *Callee = E->getCallee()->IgnoreParens(); QualType CalleeType = Callee->getType(); @@ -4156,14 +4184,13 @@ public: const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); - APValue Result; if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) || - !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, - Info, Result)) + !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, + Result, ResultSlot)) return false; - return DerivedSuccess(Result, E); + return true; } bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { @@ -4288,7 +4315,8 @@ public: } APValue ReturnValue; - EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI); + StmtResult Result = { ReturnValue, nullptr }; + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI); if (ESR != ESR_Succeeded) { // FIXME: If the statement-expression terminated due to 'return', // 'break', or 'continue', it would be nice to propagate that to @@ -5143,6 +5171,9 @@ namespace { } bool ZeroInitialization(const Expr *E); + bool VisitCallExpr(const CallExpr *E) { + return handleCallExpr(E, Result, &This); + } bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); @@ -5705,6 +5736,9 @@ namespace { return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE); } + bool VisitCallExpr(const CallExpr *E) { + return handleCallExpr(E, Result, &This); + } bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E, @@ -9224,7 +9258,7 @@ bool Expr::isPotentialConstantExpr(const HandleConstructorCall(Loc, This, Args, CD, Info, Scratch); } else HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, - Args, FD->getBody(), Info, Scratch); + Args, FD->getBody(), Info, Scratch, nullptr); return Diags.empty(); } Modified: cfe/trunk/test/PCH/cxx1y-default-initializer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1y-default-initializer.cpp?rev=246263&r1=246262&r2=246263&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx1y-default-initializer.cpp (original) +++ cfe/trunk/test/PCH/cxx1y-default-initializer.cpp Thu Aug 27 21:43:42 2015 @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -pedantic -std=c++1y %s -o %t // RUN: %clang_cc1 -pedantic -std=c++1y -emit-pch %s -o %t // RUN: %clang_cc1 -pedantic -std=c++1y -include-pch %t -verify %s Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=246263&r1=246262&r2=246263&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Aug 27 21:43:42 2015 @@ -1994,3 +1994,15 @@ namespace PR17938 { static constexpr auto z = f(Z()); } + +namespace PR24597 { + struct A { + int x, *p; + constexpr A() : x(0), p(&x) {} + constexpr A(const A &a) : x(a.x), p(&x) {} + }; + constexpr A f() { return A(); } + constexpr A g() { return f(); } + constexpr int a = *f().p; + constexpr int b = *g().p; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits